Dependency Management in Gradle

Introduction

Gradle resolves libraries from repositories into a local cache and wires them onto compile and runtime classpaths. You declare coordinates in dependencies { } using configurations such as implementation and testImplementation. This chapter adds Gson, compares configurations to Maven scopes, and shows how to inspect trees and fix conflicts.

Prerequisites

Add Gson and Parse JSON

Find coordinates on Maven Central — Gson example:

PartValue
groupcom.google.code.gson
artifactgson
version2.11.0

build.gradle:

gradle
dependencies {
    implementation 'com.google.code.gson:gson:2.11.0'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

Sync or build:

bash
./gradlew build

src/main/java/com/example/JsonDemo.java:

Run with application plugin pointing at JsonDemo, or temporarily set mainClass in build.gradle.

Configurations vs Maven Scopes

Gradle configurationTypical useMaven scope (rough)
implementationApp/runtime deps; hide from consumerscompile (modern default)
apiLibrary API exposed to dependentscompile + exported
compileOnlyNeeded to compile, not runtimeprovided
runtimeOnlyRuntime only, not compileruntime
testImplementationUnit teststest
testRuntimeOnlyTest runtime onlytest
gradle
dependencies {
    implementation 'com.google.code.gson:gson:2.11.0'
    compileOnly 'org.projectlombok:lombok:1.18.34'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

Tip

Libraries vs Apps

Application projects mostly use implementation. Java library modules use api when types from a dependency appear in public method signatures.

Version Catalog (libs.versions.toml)

Gradle 7+ supports a catalog under gradle/libs.versions.toml:

toml
[versions]
gson = "2.11.0"
junit = "5.10.2"
 
[libraries]
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }

build.gradle:

gradle
dependencies {
    implementation libs.gson
    testImplementation libs.junit.jupiter
}

One file to bump versions across modules—common in Spring Boot 3+ templates.

BOM / Platform Alignment

Import a BOM to align versions (Spring, Jackson, etc.):

gradle
dependencies {
    implementation platform('org.springframework.boot:spring-boot-dependencies:3.4.0')
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

Gradle respects BOM constraints when resolving versions.

Inspect the Dependency Tree

bash
# Full runtime classpath tree
./gradlew dependencies --configuration runtimeClasspath
 
# Compile classpath
./gradlew dependencies --configuration compileClasspath

Find why a library appeared:

bash
./gradlew dependencyInsight --dependency gson --configuration compileClasspath

Exclude Transitive Dependencies

gradle
dependencies {
    implementation('some.group:some-lib:1.0') {
        exclude group: 'commons-logging', module: 'commons-logging'
    }
}

Use when a transitive JAR causes conflicts or duplicate APIs.

Force a Version (Use Sparingly)

gradle
configurations.all {
    resolutionStrategy.force 'com.google.code.gson:gson:2.11.0'
}

Prefer BOMs or fixing the dependency that pulls the wrong version.

Reuse Maven Local Cache

If you already use Maven:

gradle
repositories {
    mavenLocal()
    mavenCentral()
}

Or global ~/.gradle/init.gradle as in IntelliJ chapter.

FAQ

Where are JARs stored?

~/.gradle/caches/modules-2/files-2.1/ (not the same path as ~/.m2 unless you use mavenLocal()).

implementation vs api?

implementation hides transitive deps from your library’s consumers; api exposes them.

Reload after editing build.gradle?

Run ./gradlew build or Reload Gradle in IDEA.

What comes next?

Gradle tasks.