Gradle offers tools to navigate the results of dependency management, allowing you to more precisely understand how and why Gradle resolves dependencies. You can render a full dependency graph, identify the origin of a given dependency, and see why specific versions were selected. Dependencies can come from build script declarations or transitive relationships.

To visualize dependencies, you can use:

  • The dependencies task

  • The dependencyInsight task

  • A Build Scan

List project dependencies using the dependencies task

Gradle provides the built-in dependencies task to render a dependency tree from the command line. By default, the task shows dependencies for all configurations within a single project. The dependency tree shows the selected version of each dependency and provides information on conflict resolution.

The dependencies task is particularly useful for analyzing transitive dependencies. While your build file lists direct dependencies, the task helps you understand which transitive dependencies are resolved during the build.

$ ./gradlew dependencies
To render the graph of dependencies declared in the buildscript classpath configuration, use the buildEnvironment task.

Understanding output annotations

$ ./gradlew :app:dependencies

> Task :app:dependencies

------------------------------------------------------------
Project ':app'
------------------------------------------------------------

annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies

compileClasspath - Compile classpath for source set 'main'.
\--- com.fasterxml.jackson.core:jackson-databind:2.17.2
     +--- com.fasterxml.jackson.core:jackson-annotations:2.17.2
     |    \--- com.fasterxml.jackson:jackson-bom:2.17.2
     |         +--- com.fasterxml.jackson.core:jackson-annotations:2.17.2 (c)
     |         +--- com.fasterxml.jackson.core:jackson-core:2.17.2 (c)
     |         \--- com.fasterxml.jackson.core:jackson-databind:2.17.2 (c)
     +--- com.fasterxml.jackson.core:jackson-core:2.17.2
     |    \--- com.fasterxml.jackson:jackson-bom:2.17.2 (*)
     \--- com.fasterxml.jackson:jackson-bom:2.17.2 (*)

...

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.

Specifying a dependency configuration

To focus on a specific dependency configuration, use the optional --configuration parameter.

Like project and task names, Gradle allows abbreviated names for dependency configurations. For example, you can use tRC instead of testRuntimeClasspath, as long as it matches a unique configuration.

The following examples display dependencies for the testRuntimeClasspath configuration in a Java project:

$ gradle -q dependencies --configuration testRuntimeClasspath
$ gradle -q dependencies --configuration tRC

To view a list of all configurations in a project, including those provided by plugins, run the resolvableConfigurations report. For more details, refer to the plugin’s documentation, such as the Java Plugin here.

Looking at an 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
configurations {
    create("scm")
}

dependencies {
    "scm"("org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r")
}
build.gradle
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 selected version using the dependencyInsight task

A project may request two different versions of the same dependency either directly or transitively that may result in a version conflict.

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'
}

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 reason and origin for its version selection.

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.

--all-variants (optional)

Render information about all variants, not only the selected variant.

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.

Understanding the selection reasons

The "Selection reasons" section of the dependency insight report lists the reasons why a dependency was selected.

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.

Get a holistic view using Build Scans

The dependency tree in a Build Scan shows information about conflicts.

A Build Scan was created for the commons-codec example above and a URL was provided with the results.

Head over to the Dependencies tab and navigate to your desired dependency. Select the Required By tab to see the selection reason and origin of the dependency:

dependency management dependency insight report build scan