:metadata-file-spec: https://github.com/gradle/gradle/blob/master/subprojects/docs/src/docs/design/gradle-module-metadata-latest-specification.md

[[understanding-variant-selection]]
= Understanding variant selection 

In other dependency management engines, like Apache Maven™, dependencies and artifacts are bound to a component that is published at a particular GAV (group-artifact-version) coordinates.
The set of dependencies for this component are always the same, regardless of which artifact may be used from the component.

If the component does have multiple artifacts, each one is identified by a cumbersome _classifier_.
There are no common semantics associated with classifiers and that makes it difficult to guarantee a globally consistent dependency graph.
This means that nothing prevents multiple artifacts for a single component (e.g., `jdk7` and `jdk8` classifiers) from appearing in a classpath and causing hard to diagnose problems.

== Maven component model

.The Maven component model
image::component-model-maven.png[]

== Gradle component model

.The Gradle component model
image::component-model-gradle.png[]

Gradle's dependency management engine is _variant aware_.

In addition to a component, Gradle has the concept of _variants_ of a component.
Variants correspond to the different ways a component can be used, such as for Java compilation or native linking or documentation.
Artifacts are attached to a _variant_ and each variant can have a different set of dependencies:

How does Gradle know which variant to choose when there's more than one?
Variants are matched by use of <<variant_attributes.adoc#variant_attributes,attributes>>, which provide semantics to the variants and help the engine to produce a _consistent_ resolution result.

Gradle differentiates between two kind of components:
- local components (like projects), built from sources
- external components, published to repositories

For local components, <<#sec:abm_configuration_attributes, variants are mapped to consumable configurations>>.
For external components, variants are defined by published Gradle Module Metadata or <<#sec:mapping-maven-ivy-to-variants,are derived from Ivy/Maven metadata>>.

[NOTE]
.Variants vs configurations
====
Variants and configurations are sometimes used interchangeably in the documentation, DSL or API for historical reasons.

All components provide _variants_ and those variants may be backed by a consumable configuration.
Not all configurations are variants because they may be used for declaring or resolving dependencies.
====

[[sec:abm_configuration_attributes]]
== Variant attributes

<<variant_attributes.adoc#variant_attributes,Attributes>> are type-safe key-value pairs that are defined by the consumer (for a resolvable configuration) and the producer (for each variant).

The consumer can define any number of attributes.
Each attribute helps narrow the possible variants that can be selected.
Attribute values do not need to be exact matches. 

The variant can also define any number of attributes.
The attributes should describe how the variant is intended to be used.
For example, Gradle uses an attribute named `org.gradle.usage` to describe with how a component is used by the consumer (for compilation, for runtime execution, etc). 
It is not unusual for a variant to have more attributes than the consumer needs to provide to select it.

[[sec:variant-aware-matching]]
== Variant attribute matching

[NOTE]
.About producer variants
====
The variant _name_ is mostly for debugging purposes and error messages.
The name does not participate variant matching--only its attributes do.
====

There are no restrictions on the number of variants a component can define.
Usually, a component has at least an implementation variant, but it could also expose test fixtures, documentation or source code.
A component may also expose _different variants_ for different consumers for the same usage. For example, when compiling, a component could have different headers for Linux vs Windows vs macOS.

Gradle performs _variant aware selection_ by matching the attributes requested by the consumer against attributes defined by the producer. The <<variant_attributes.adoc#sec:abm_algorithm, selection algorithm>> is detailed in another section.

[NOTE]
====
There are two exceptions to this rule that bypass variant aware resolution:
- when a producer has no variants, a default artifact is chosen.
- when a consumer _explicitly selects a configuration by name_, the artifacts of the configuration are chosen.
====

== A simple example

Let's consider an example where a consumer is trying to use a library for compilation. 

First, the consumer needs to explain how it's going to use the result of dependency resolution. This is done by setting _attributes_ on the resolvable configuration of the consumer.

The consumer wants to resolve a variant that matches:
- `org.gradle.usage=JAVA_API`

Second, the producer needs to expose the different variants of the component.

The producer component exposes 2 variants: 
- its API (named `apiElements`) with attribute `org.gradle.usage=JAVA_API`
- its runtime (named `runtimeElements`) with attribute `org.gradle.usage=JAVA_RUNTIME`

Finally, Gradle selects the appropriate variant by looking at the variant attributes:
- the consumer wants a variant with attributes `org.gradle.usage=JAVA_API`
- the producer has a matching variant (`apiElements`)
- the producer has a non-matching variant (`runtimeElements`)

Gradle provides the artifacts and dependencies from the `apiElements` variant to the consumer.

== A more complicated example

In the real world, consumers and producers have more than one attribute.

A Java Library project in Gradle will involve several different attributes

- `org.gradle.usage` that describes how the variant is used
- `org.gradle.dependency.bundling` that describes how the variant handles dependencies (shadow jar vs fat jar vs regular jar)
- `org.gradle.libraryelements`, that describes the packaging of the variant (classes or jar)
- `org.gradle.jvm.version` that describes the _minimal version_ of Java this variant targets
- `org.gradle.jvm.environment` that describes the type of JVM this variant targets

Let's consider an example where the consumer wants to run tests with a library on Java 8 and the producer supports two different Java versions (Java 8 and Java 11).

First, the consumer needs to explain which version of the Java it needs.

The consumer wants to resolve a variant that:
- can be used at runtime (has `org.gradle.usage=JAVA_RUNTIME`)
- can be run on _at least_ Java 8 (`org.gradle.jvm.version=8`)

Second, the producer needs to expose the different variants of the component.

Like in the simple example, there is both a API (compilation) and runtime variant. These exist for both the Java 8 and Java 11 version of the component.
- its API for Java 8 consumers (named `apiJava8Elements`) with attribute `org.gradle.usage=JAVA_API` and `org.gradle.jvm.version=8`
- its runtime for Java 8 consumers (named `runtime8Elements`) with attribute `org.gradle.usage=JAVA_RUNTIME` and `org.gradle.jvm.version=8`
- its API for Java 11 consumers (named `apiJava11Elements`) with attribute `org.gradle.usage=JAVA_API` and `org.gradle.jvm.version=11`
- its runtime for Java 11 consumers (named `runtime11Elements`) with attribute `org.gradle.usage=JAVA_RUNTIME` and `org.gradle.jvm.version=11`

Finally, Gradle selects the best matching variant by looking at all of the attributes:
- the consumer wants a variant with compatible attributes to `org.gradle.usage=JAVA_RUNTIME` and `org.gradle.jvm.version=8`
- the variants `runtime8Elements` and `runtime11Elements` have `org.gradle.usage=JAVA_RUNTIME`
- the variants `apiJava8Elements` and `apiJava11Elements` are incompatible
- the variant `runtime8Elements` is compatible because it can run on Java 8
- the variant `runtime11Elements` is incompatible because it cannot run on Java 8

Gradle provides the artifacts and dependencies from the `runtime8Elements` variant to the consumer.

[NOTE]
.Compatibility of variants
====
What if the consumer sets `org.gradle.jvm.version` to 7?

Dependency resolution would _fail_ with an error message explaining that there's no suitable variant.
Gradle recognizes that the consumer wants a Java 7 compatible library and the _minimal_ version of Java available on the producer is 8.

If the consumer requested `org.gradle.jvm.version=15`, then Gradle knows either the Java 8 or Java 11 variants could work. Gradle select the highest compatible Java version (11).
====

[[sec:variant-select-errors]]
== Variant selection errors

When selecting the most compatible variant of a component, resolution may fail:
* when more than one variant from the producer matches the consumer attributes (ambiguity error)
* when no variants from the producer match the consumer attributes (incompatibility error)

[[sub:variant-ambiguity]]
=== Dealing with ambiguity errors

An ambiguous variant selection looks like the following:

[listing]
----
> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve project :lib.
     Required by:
         project :ui
      > Cannot choose between the following variants of project :lib:
          - feature1ApiElements
          - feature2ApiElements
        All of them match the consumer attributes:
          - Variant 'feature1ApiElements' capability org.test:test-capability:1.0:
              - Unmatched attribute:
                  - Found org.gradle.category 'library' but wasn't required.
              - Compatible attributes:
                  - Provides org.gradle.dependency.bundling 'external'
                  - Provides org.gradle.jvm.version '11'
                  - Required org.gradle.libraryelements 'classes' and found value 'jar'.
                  - Provides org.gradle.usage 'java-api'
          - Variant 'feature2ApiElements' capability org.test:test-capability:1.0:
              - Unmatched attribute:
                  - Found org.gradle.category 'library' but wasn't required.
              - Compatible attributes:
                  - Provides org.gradle.dependency.bundling 'external'
                  - Provides org.gradle.jvm.version '11'
                  - Required org.gradle.libraryelements 'classes' and found value 'jar'.
                  - Provides org.gradle.usage 'java-api'
----

All _compatible_ candidate variants are displayed with their attributes.

* Unmatched attributes are presented first, as they might be the missing piece in selecting the proper variant.
* Compatible attributes are presented second as they indicate what the consumer wanted and how these variants do match that request.
* There will not be any incompatible attributes as the variant would not be considered a candidate.

In the example above, the fix does not lie in attribute matching but in <<dependency_capability_conflict.adoc#sub:selecting-between-candidates,capability matching>>, which are shown next to the variant name.
Because these two variants effectively provide the same attributes and capabilities, they cannot be disambiguated.
So in this case, the fix is most likely to provide different capabilities on the producer side (`project :lib`) and express a capability choice on the consumer side (`project :ui`).

[[sub:variant-no-match]]
=== Dealing with no matching variant errors

A no matching variant error looks like the following:

[listing]
----
> No variants of project :lib match the consumer attributes:
  - Configuration ':lib:compile':
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attribute:
          - Provides usage 'api'
  - Configuration ':lib:compile' variant debug:
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attributes:
          - Found buildType 'debug' but wasn't required.
          - Provides usage 'api'
  - Configuration ':lib:compile' variant release:
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attributes:
          - Found buildType 'release' but wasn't required.
          - Provides usage 'api'
----

All _compatible_ candidate variants are displayed with their attributes.

* Incompatible attributes are presented first, as they usually are the key in understanding why a variant could not be selected.
* Other attributes are presented second, this includes _required_ and _compatible_ ones as well as all extra _producer_ attributes that are not requested by the consumer.

Similar to the ambiguous variant error, the goal is to understand which variant should be selected. In some cases, there may not be any compatible variants from the producer (e.g., trying to run on Java 8 with a library built for Java 11). 

[[sec:variant-visual]]
== Visualizing variant information

=== Outgoing variants report

The report task `outgoingVariants` shows the list of variants available for selection by consumers of the project. It displays the capabilities, attributes and artifacts for each variant. 

This task is similar to the `dependencyInsight` <<viewing_debugging_dependencies.adoc#sec:identifying_reason_dependency_selection,reporting task>>.

By default, `outgoingVariants` prints information about all variants.
It offers the optional parameter `--variant <variantName>` to select a single variant to display.
It also accepts the `--all` flag to include information about legacy and deprecated configurations.

Here is the output of the `outgoingVariants` task on a freshly generated `java-library` project:

[listing]
----
> Task :outgoingVariants
--------------------------------------------------
Variant apiElements
--------------------------------------------------
Description = API elements for main.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-api
Artifacts
    - build/libs/lib.jar (artifactType = jar)

Secondary Variants (*)

    --------------------------------------------------
    Secondary Variant classes
    --------------------------------------------------
        Description = Directories containing compiled class files for main.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = classes
            - org.gradle.usage               = java-api
        Artifacts
            - build/classes/java/main (artifactType = java-classes-directory)

--------------------------------------------------
Variant mainSourceElements (i)
--------------------------------------------------
Description = List of source directories contained in the Main SourceSet.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = verification
    - org.gradle.dependency.bundling = external
    - org.gradle.verificationtype    = main-sources
Artifacts
    - src/main/java (artifactType = directory)
    - src/main/resources (artifactType = directory)

--------------------------------------------------
Variant runtimeElements
--------------------------------------------------
Description = Elements of runtime for main.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Artifacts
    - build/libs/lib.jar (artifactType = jar)

Secondary Variants (*)

    --------------------------------------------------
    Secondary Variant classes
    --------------------------------------------------
        Description = Directories containing compiled class files for main.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = classes
            - org.gradle.usage               = java-runtime
        Artifacts
            - build/classes/java/main (artifactType = java-classes-directory)

    --------------------------------------------------
    Secondary Variant resources
    --------------------------------------------------
        Description = Directories containing the project's assembled resource files for use at runtime.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = resources
            - org.gradle.usage               = java-runtime
        Artifacts
            - build/resources/main (artifactType = java-resources-directory)

--------------------------------------------------
Variant testResultsElementsForTest (i)
--------------------------------------------------
Description = Directory containing binary results of running tests for the test Test Suite's test target.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category              = verification
    - org.gradle.testsuite.name        = test
    - org.gradle.testsuite.target.name = test
    - org.gradle.testsuite.type        = unit-test
    - org.gradle.verificationtype      = test-results
Artifacts
    - build/test-results/test/binary (artifactType = directory)

(i) Configuration uses incubating attributes such as Category.VERIFICATION.
(*) Secondary variants are variants created via the Configuration#getOutgoing(): ConfigurationPublications API which also participate in selection, in addition to the configuration itself.
----

From this you can see the two main variants that are exposed by a java library, `apiElements` and `runtimeElements`.
Notice that the main difference is on the `org.gradle.usage` attribute, with values `java-api` and `java-runtime`.
As they indicate, this is where the difference is made between what needs to be on the _compile_ classpath of consumers, versus what's needed on the _runtime_ classpath.

It also shows _secondary_ variants, which are exclusive to Gradle projects and not published.
For example, the secondary variant `classes` from `apiElements` is what allows Gradle to skip the JAR creation when compiling against a <<java_library_plugin.adoc#sec:java_library_classes_usage,`java-library` project>>.

=== Resolvable configurations report

Gradle also offers a complimentary report task called `resolvableConfigurations` that displays the _resolvable_ configurations of a project, which are those which can have dependencies added and be resolved.  The report will list their attributes and any configurations that they extend.  It will also list a summary of any attributes which will be affected by <<variant_attributes.adoc#sec:abm_compatibility_rules, Compatibility Rules>> or <<variant_attributes.adoc#sec:abm_disambiguation_rules, Disambiguation Rules>> during resolution.

By default, `resolvableConfigurations` prints information about all purely resolvable configurations.
These are configurations that are marked resolvable but *not* marked consumable.
Though some resolvable configurations are also marked consumable, these are legacy configurations that should *not* have dependencies added in build scripts.
This report offers the optional parameter `--configuration <configurationName>` to select a single configuration to display.
It also accepts the `--all` flag to include information about legacy and deprecated configurations.
Finally, it accepts the `--recursive` flag to list in the extended configurations section those configurations which are extended _transitively_ rather than directly.

Here is the output of the `resolvableConfigurations` task on a freshly generated `java-library` project:

[listing]
----
> Task :resolvableConfigurations
--------------------------------------------------
Configuration annotationProcessor
--------------------------------------------------
Description = Annotation processors and their dependencies for source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime

--------------------------------------------------
Configuration compileClasspath
--------------------------------------------------
Description = Compile classpath for source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = classes
    - org.gradle.usage               = java-api
Extended Configurations
    - compileOnly
    - implementation

--------------------------------------------------
Configuration runtimeClasspath
--------------------------------------------------
Description = Runtime classpath of source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Extended Configurations
    - implementation
    - runtimeOnly

--------------------------------------------------
Configuration testAnnotationProcessor
--------------------------------------------------
Description = Annotation processors and their dependencies for source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime

--------------------------------------------------
Configuration testCompileClasspath
--------------------------------------------------
Description = Compile classpath for source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = classes
    - org.gradle.usage               = java-api
Extended Configurations
    - testCompileOnly
    - testImplementation

--------------------------------------------------
Configuration testRuntimeClasspath
--------------------------------------------------
Description = Runtime classpath of source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Extended Configurations
    - testImplementation
    - testRuntimeOnly

--------------------------------------------------
Compatibility Rules
--------------------------------------------------
Description = The following Attributes have compatibility rules defined.

    - org.gradle.dependency.bundling
    - org.gradle.jvm.environment
    - org.gradle.jvm.version
    - org.gradle.libraryelements
    - org.gradle.plugin.api-version
    - org.gradle.usage

--------------------------------------------------
Disambiguation Rules
--------------------------------------------------
Description = The following Attributes have disambiguation rules defined.

    - org.gradle.category
    - org.gradle.dependency.bundling
    - org.gradle.jvm.environment
    - org.gradle.jvm.version
    - org.gradle.libraryelements
    - org.gradle.plugin.api-version
    - org.gradle.usage
----

From this you can see the two main configurations used to resolve dependencies, `compileClasspath` and `runtimeClasspath`, as well as their corresponding test configurations.

[[sec:mapping-maven-ivy-to-variants]]
== Mapping from Maven/Ivy to Gradle variants

Neither Maven nor Ivy have the concept of _variants_, which are only natively supported by Gradle Module Metadata.
Gradle can still work with Maven and Ivy by using different variant derivation strategies.

[NOTE]
.Relationship with Gradle Module Metadata
====
Gradle Module Metadata is a metadata format for modules published on Maven, Ivy and other kinds of repositories.
It is similar to the `pom.xml` or `ivy.xml` metadata file, but this format contains details about variants.

See the {metadata-file-spec}[Gradle Module Metadata specification] for more information.
====

[[sub:maven-mapping-to-variants]]
=== Mapping of Maven POM metadata to variants

Modules published on a Maven repository are automatically converted into variant-aware modules.

There is no way for Gradle to know which kind of component was published:
- a BOM that represents a Gradle platform
- a BOM used as a super-POM
- a POM that is both a platform _and_ a library

The default strategy used by Java projects in Gradle is to derive 8 different variants:

* 2 "library" variants (attribute `org.gradle.category` = `library`)
** the `compile` variant maps the `<scope>compile</scope>` dependencies.
This variant is equivalent to the `apiElements` variant of the <<java_library_plugin.adoc#java_library_plugin,Java Library plugin>>.
All dependencies of this scope are considered _API dependencies_.
** the `runtime` variant maps both the `<scope>compile</scope>` and `<scope>runtime</scope>` dependencies.
This variant is equivalent to the `runtimeElements` variant of the <<java_library_plugin.adoc#java_library_plugin,Java Library plugin>>.
All dependencies of those scopes are considered _runtime dependencies_.
- in both cases, the `<dependencyManagement>` dependencies are _not converted to constraints_
* a "sources" variant that represents the sources jar for the component
* a "javadoc" variant that represents the javadoc jar for the component
* 4 "platform" variants derived from the `<dependencyManagement>` block (attribute `org.gradle.category` = `platform`):
** the `platform-compile` variant maps the  `<scope>compile</scope>` dependency management dependencies as _dependency constraints_.
** the `platform-runtime` variant maps both the `<scope>compile</scope>` and `<scope>runtime</scope>` dependency management dependencies as _dependency constraints_.
** the `enforced-platform-compile` is similar to `platform-compile` but all the constraints are _forced_
** the `enforced-platform-runtime` is similar to `platform-runtime` but all the constraints are _forced_

You can understand more about the use of platform and enforced platforms variants by looking at the <<platforms.adoc#sub:bom_import, importing BOMs>> section of the manual.
By default, whenever you declare a dependency on a Maven module, Gradle is going to look for the `library` variants.
However, using the `platform` or `enforcedPlatform` keyword, Gradle is now looking for one of the "platform" variants, which allows you to import the constraints from the POM files, instead of the dependencies.

[[sub:ivy-mapping-to-variants]]
=== Mapping of Ivy files to variants

Gradle has no built-in derivation strategy implemented for Ivy files.
Ivy is a flexible format that allows you to publish arbitrary files and can be heavily customized.

If you want to implement a derivation strategy for _compile_ and _runtime_ variants for Ivy, you can do so with <<component_metadata_rules.adoc#sec:component_metadata_rules,component metadata rule>>.
The component metadata rules API allows you to <<component_metadata_rules.adoc#sec:component_metadata_rules_details,access Ivy configurations>> and create variants based on them.
If you know that all the Ivy modules your are consuming have been published with Gradle without further customizations of the `ivy.xml` file, you can add the following rule to your build:

.Deriving compile and runtime variants for Ivy metadata
====
include::sample[dir="snippets/dependencyManagement/customizingResolution-ivyMetadataRule/groovy",files="build.gradle[tags=ivy-component-metadata-rule]"]
include::sample[dir="snippets/dependencyManagement/customizingResolution-ivyMetadataRule/kotlin",files="build.gradle.kts[tags=ivy-component-metadata-rule]"]
====

The rule creates an `apiElements` variant based on the `compile` configuration and a `runtimeElements` variant based on the `default` configuration of each ivy module.
For each variant, it sets the corresponding <<#sec:variant-aware-matching,Java ecosystem attributes>>.
Dependencies and artifacts of the variants are taken from the underlying configurations.
If not all consumed Ivy modules follow this pattern, the rule can be adjusted or only applied to a selected set of modules.

For all Ivy modules without variants, Gradle has a fallback selection method. Gradle does _not_ perform variant aware resolution and instead selects either the `default` configuration or an explicitly named configuration.
