Gradle provides tooling to navigate dependency graphs and mitigate dependency hell. Users can render the full graph of dependencies as well as identify the selection reason and origin for a dependency. Dependencies can originate through build script declared dependencies or transitive dependencies. You can visualize dependencies with:

  • the built-in Gradle CLI dependencies task

  • the built-in Gradle CLI dependencyInsight task

  • build scans

List Project Dependencies

Gradle provides the built-in dependencies task to render a dependency tree from the command line. By default, the dependency tree renders dependencies for all configurations within a single project. The dependency tree indicates the selected version of each dependency. It also displays information about dependency conflict resolution.

The dependencies task can be especially helpful for issues related to transitive dependencies. Your build file lists direct dependencies, but the dependencies task can help you understand which transitive dependencies resolve during your build.

Graph of dependencies declared in the buildscript classpath configuration can be rendered using task buildEnvironment.

Output Annotations

The dependencies task marks dependency trees with the following annotations:

  • (*): Indicates repeated occurrences of a transitive dependency subtree. Gradle expands transitive dependency subtrees only once per project; repeat occurrences only display the root of the subtree, followed by this annotation.

  • (c): This element is a dependency constraint, not a dependency. Look for the matching dependency elsewhere in the tree.

  • (n): A dependency or dependency configuration that cannot be resolved.

Specify a Dependency Configuration

To focus on the information about one dependency configuration, provide the optional parameter --configuration. Just like project and task names, Gradle accepts abbreviated names to select a dependency configuration. For example, you can specify tRC instead of testRuntimeClasspath if the pattern matches to a single dependency configuration. Both of the following examples show dependencies in the testRuntimeClasspath dependency configuration of a Java project:

> gradle -q dependencies --configuration testRuntimeClasspath
> gradle -q dependencies --configuration tRC

To see a list of all the configurations available in a project, including those added by any plugins, you can run a resolvableConfigurations report.

For more info, see that plugin’s documentation (for instance, the Java Plugin is documented here).

Example

Consider a project that uses the JGit library to execute Source Control Management (SCM) operations for a release process. You can declare dependencies for external tooling with the help of a custom dependency configuration. This avoids polluting other contexts, such as the compilation classpath for your production source code.

The following example declares a custom dependency configuration named "scm" that contains the JGit dependency:

build.gradle.kts
repositories {
    mavenCentral()
}

configurations {
    create("scm")
}

dependencies {
    "scm"("org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r")
}
build.gradle
repositories {
    mavenCentral()
}

configurations {
    scm
}

dependencies {
    scm 'org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r'
}

Use the following command to view a dependency tree for the scm dependency configuration:

> gradle -q dependencies --configuration scm

------------------------------------------------------------
Root project 'dependencies-report'
------------------------------------------------------------

scm
\--- org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r
     +--- com.jcraft:jsch:0.1.54
     +--- com.googlecode.javaewah:JavaEWAH:1.1.6
     +--- org.apache.httpcomponents:httpclient:4.3.6
     |    +--- org.apache.httpcomponents:httpcore:4.3.3
     |    +--- commons-logging:commons-logging:1.1.3
     |    \--- commons-codec:commons-codec:1.6
     \--- org.slf4j:slf4j-api:1.7.2

A web-based, searchable dependency report is available by adding the --scan option.

Identify the Dependency Version Selected

A project may request two different versions of the same dependency either directly or transitively. Gradle applies version conflict resolution to ensure that only one version of the dependency exists in the dependency graph. The following example introduces a conflict with commons-codec:commons-codec, added both as a direct dependency and a transitive dependency of JGit:

build.gradle.kts
repositories {
    mavenCentral()
}

configurations {
    create("scm")
}

dependencies {
    "scm"("org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r")
    "scm"("commons-codec:commons-codec:1.7")
}
build.gradle
repositories {
    mavenCentral()
}

configurations {
    scm
}

dependencies {
    scm 'org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r'
    scm 'commons-codec:commons-codec:1.7'
}

The dependency tree in a build scan shows information about conflicts. Click on a dependency and select the "Required By" tab to see the selection reason and origin of the dependency.

dependency management dependency insight report build scan

Dependency Insights

Gradle provides the built-in dependencyInsight task to render a dependency insight report from the command line. Dependency insights provide information about a single dependency within a single configuration. Given a dependency, you can identify the selection reason and origin.

dependencyInsight accepts the following parameters:

--dependency <dependency> (mandatory)

The dependency to investigate. You can supply a complete group:name, or part of it. If multiple dependencies match, Gradle generates a report covering all matching dependencies.

--configuration <name> (mandatory)

The dependency configuration which resolves the given dependency. This parameter is optional for projects that use the Java plugin, since the plugin provides a default value of compileClasspath.

--single-path (optional)

Render only a single path to the dependency.

The following code snippet demonstrates how to run a dependency insight report for all paths to a dependency named "commons-codec" within the "scm" configuration:

> gradle -q dependencyInsight --dependency commons-codec --configuration scm
commons-codec:commons-codec:1.7
  Variant default:
    | Attribute Name    | Provided | Requested |
    |-------------------|----------|-----------|
    | org.gradle.status | release  |           |
   Selection reasons:
      - By conflict resolution: between versions 1.7 and 1.6

commons-codec:commons-codec:1.7
\--- scm

commons-codec:commons-codec:1.6 -> 1.7
\--- org.apache.httpcomponents:httpclient:4.3.6
     \--- org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r
          \--- scm

A web-based, searchable dependency report is available by adding the --scan option.

For more information about configurations, see the dependency configuration documentation.

Selection Reasons

The "Selection reasons" section of the dependency insight report lists the reasons why a dependency was selected. Have a look at the table below to understand the meaning of the different terms used:

Table 1. Terminology
Reason Meaning

(Absent)

No reason other than a reference, direct or transitive, was present.

Was requested : <text>

The dependency appears in the graph, and the inclusion came with a because text.

Was requested : didn’t match versions <versions>

The dependency appears with a dynamic version which did not include the listed versions. May be followed by a because text.

Was requested : reject version <versions>

The dependency appears with a rich version containing one or more reject. May be followed by a because text.

By conflict resolution : between versions <version>

The dependency appeared multiple times, with different version requests. This resulted in conflict resolution to select the most appropriate version.

By constraint

A dependency constraint participated in the version selection. May be followed by a because text.

By ancestor

There is a rich version with a strictly which enforces the version of this dependency.

Selected by rule

A dependency resolution rule overruled the default selection process. May be followed by a because text.

Rejection : <version> by rule because <text>

A ComponentSelection.reject rejected the given version of the dependency.

Rejection: version <version>: <attributes information>

The dependency has a dynamic version and some versions did not match the requested attributes.

Forced

The build enforces the version of the dependency through an enforced platform or resolution strategy.

If multiple selection reasons exist, the insight report lists all of them.

Troubleshooting

Version Conflicts

If the selected version does not match your expectation, Gradle offers a series of tools to help you control transitive dependencies.

Variant Selection Errors

Sometimes a selection error happens at the variant selection level. Have a look at the dedicated section to understand these errors and how to resolve them.

Unsafe Configuration Resolution Errors

Resolving a configuration can have side effects on Gradle’s project model. As a result, Gradle must manage access to each project’s configurations. There are a number of ways a configuration might be resolved unsafely. For example:

  • A task from one project directly resolves a configuration in another project in the task’s action.

  • A task specifies a configuration from another project as an input file collection.

  • A build script for one project resolves a configuration in another project during evaluation.

  • Project configurations are resolved in the settings file.

Gradle produces a deprecation warning for each unsafe access. Unsafe access can cause indeterminate errors. You should fix unsafe access warnings in your build.

In most cases, you can resolve unsafe accesses by creating a cross-project dependency on the other project. See the documentation for sharing outputs between projects for more information.

If you find a use case that can’t be resolved using these techniques, please let us know by filing a GitHub Issue.