In Gradle, how do I declare common dependencies in a single place?

GradleDependency ManagementGradle Dependencies

Gradle Problem Overview


In Maven there is a very useful feature where you can define a dependency in the <dependencyManagement> section of the parent POM, and reference that dependency from child modules without specifying the version or scope or whatever.

What are the alternatives in Gradle?

Gradle Solutions


Solution 1 - Gradle

You can declare common dependencies in a parent script:

ext.libraries = [ // Groovy map literal
    spring_core: "org.springframework:spring-core:3.1",
    junit: "junit:junit:4.10"
]

From a child script, you can then use the dependency declarations like so:

dependencies {
    compile libraries.spring_core
    testCompile libraries.junit
}

To share dependency declarations with advanced configuration options, you can use DependencyHandler.create:

libraries = [
    spring_core: dependencies.create("org.springframework:spring-core:3.1") {
        exclude module: "commons-logging"
        force = true
    }
]

Multiple dependencies can be shared under the same name:

libraries = [
    spring: [ // Groovy list literal
        "org.springframework:spring-core:3.1", 
        "org.springframework:spring-jdbc:3.1"
    ]
]

dependencies { compile libraries.spring } will then add both dependencies at once.

The one piece of information that you cannot share in this fashion is what configuration (scope in Maven terms) a dependency should be assigned to. However, from my experience it is better to be explicit about this anyway.

Solution 2 - Gradle

As of Gradle 4.6, dependency constraints are suggested in the documentation as the way to achieve this. From https://docs.gradle.org/current/userguide/declaring_dependencies.html#declaring_a_dependency_without_version:

> A recommended practice for larger projects is to declare dependencies without versions and use dependency constraints for version declaration. The advantage is that dependency constraints allow you to manage versions of all dependencies, including transitive ones, in one place.

In your parent build.gradle file:

allprojects {
  plugins.withType(JavaPlugin).whenPluginAdded {
    dependencies {
      constraints {
        implementation("com.google.guava:guava:27.0.1-jre")
      }
    }
  }
}

Wrapping the dependencies block with a check for the Java plugin (... whenPluginAdded {) isn't strictly necessary, but it will then handle adding a non-Java project to the same build.

Then in a child gradle project you can simply omit the verison:

apply plugin: "java"

dependencies {
  implementation("com.google.guava:guava")
}

Child builds can still choose to specify a higher version. If a lower version is specified it is automatically upgraded to the version in the constraint.

Solution 3 - Gradle

It's a late reply, yet you might also want to have a look at: http://plugins.gradle.org/plugin/io.spring.dependency-management It provides possibility to import a maven 'bom', and reuse the definitions defined in the 'bom'. It's certainly a nice help when gradually migrating from maven to gradle ! Enjoying it right now.

Solution 4 - Gradle

io.spring.gradle:dependency-management-plugin plugin has problems with new Gradle 3.x series but stable for 2.x series. For reference look to bug report Drop support for Gradle 3 #115

In case of Spring (main promoter of BOM usage) you may end with:

buildscript {
    repositories {
        mavenLocal()
        jcenter()
    }
    dependencies {
        classpath 'io.spring.gradle:dependency-management-plugin:1.0.0.RELEASE'
    }
}

repositories {
    mavenLocal()
    jcenter()
}

apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'

dependencyManagement {
    imports {
        mavenBom 'io.spring.platform:platform-bom:Athens-SR3'
    }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'

    testCompile 'org.springframework.boot:spring-boot-starter-test'
}

Note that io.spring.platform:platform-bom have org.springframework.boot:spring-boot-starter-parent as parent so it is compatable with Spring Boot

You can verify actual dependency resolution via:

$ gradle dependencies
$ gradle dependencies --configuration compile
$ gradle dependencies -p $SUBPROJ

$ gradle buildEnvironment
$ gradle buildEnvironment -p $SUBPROJ

or with task:

task showMeCache {
    configurations.compile.each { println it }
}

Read official Soring blog post Better dependency management for Gradle to understand the reason of introducing io.spring.gradle:dependency-management-plugin.

Solution 5 - Gradle

I'll prefer to create common_dependencies.gradle file in root project with content

buildscript {
ext {
    commonDependencies = [
            redis      : 'redis.clients:jedis:3.6.3',
            lettuce    : 'io.lettuce:lettuce-core:6.1.4.RELEASE'
      ]
   }
}

then in root/submodule's build.gradle

apply from: rootProject.file("common_dependencies.gradle")

dependencies {
    commonDependencies.values().forEach {
        implementation it
    }
}

Solution 6 - Gradle

Solution 7 - Gradle

You can centralize a dependency using below code :

In gradle.properties

COMPILE_SDK_VERSION=26
BUILD_TOOLS_VERSION=26.0.1
TARGET_SDK_VERSION=26
MIN_SDK_VERSION=14

ANDROID_SUPPORT_VERSION=26.0.2

In each module add to build.gradle:

android {
    compileSdkVersion COMPILE_SDK_VERSION as int
    buildToolsVersion BUILD_TOOLS_VERSION as String

    defaultConfig {
        minSdkVersion MIN_SDK_VERSION as int
        targetSdkVersion TARGET_SDK_VERSION as int
        versionCode 1
        versionName "1.0"

    }
    
}

dependencies {
 compile "com.android.support:appcompat-v7:${ANDROID_SUPPORT_VERSION}"
 compile "com.android.support:support-v4:${ANDROID_SUPPORT_VERSION}"
 compile "com.android.support:support-annotations:${ANDROID_SUPPORT_VERSION}"
 compile "com.android.support:support-vector-drawable:${ANDROID_SUPPORT_VERSION}"
 compile "com.android.support:design:${ANDROID_SUPPORT_VERSION}"
}

Solution 8 - Gradle

This blog post suggest managing dependencies and groups as configurations: https://www.javacodegeeks.com/2016/05/manage-dependencies-gradle-multi-project-build.html

I have not tried it myself, but it looks interesting.

Root project build.gradle

subprojects {
  configurations {
    commonsIo
  }
 
  dependencies {
    commonsIo 'commons-io:commons-io:2.5'
  }
}

Sub-project build.gradle

configurations {
  compile.extendsFrom commonsIo
}

Solution 9 - Gradle

As datta said in their answer, Gradle now has something called version catalogs.
Here is an example for Kotlin DSL (*.kts). Note that I'm using Gradle 7.4.

Defining dependencies in settings.gradle.kts:

// Configure dependencies aspects applied to all projects
dependencyResolutionManagement {
    // By default, repositories declared by a project will override the ones here.
    // You can change this behavior with the repositoriesMode property.
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)

    // Define repositories for all projects
    repositories {
        mavenCentral()
        maven("https://jitpack.io")
    }

    versionCatalogs {
        create("libs") {
            // Versions are useful specially when you have libraries with the same
            // group and version which are updated together with the same version
            version("room", "2.4.1")
            //       │       │
            //       │       └───> The version notation
            //       └───> Your desired name (alias)
    
            library("material", "com.google.android.material:material:1.4.0")
            //       │           │
            //       │           └───> The dependency notation (coordinates)
            //       ├───> Your desired name (alias); only letters, digits and _ - .
            //       └───> Note that _ - . will all be normalized to .
    
            // You can configure the version as you would in regular build file
            // Note that the group and module are separate parameters
            library("junit5", "org.junit.jupiter", "junit-jupiter").version {
                prefer("5.8.0")
            }
    
            // Using the same version for multiple dependencies
            library("room-ktx", "androidx.room", "room-ktx").versionRef("room")
            library("room-runtime", "androidx.room", "room-runtime").versionRef("room")
        }
    }
}

Usage in build.gradle.kts:

dependencies {
    implementation(libs.material)
    implementation(libs.room.ktx)
    implementation(libs.room.runtime)
    testImplementation(libs.junit5)
}

As you can see, not only can you declare dependencies, but also you can declare the repositories here as well (instead of using allprojects block in your top-level build script to define repositories for all subprojects).

For groovy syntax of above solution and for more information about version catalogs and centralizing your repository and dependency configurations, see Gradle official guides.

Solution 10 - Gradle

To keep you gradle file clean, we can group dependency in an array and implement them later.

  1. Add version of libraries like this in build.gradle (app level) outside of dependency block:

> // declare versions of library > > final RetrofitVersion = '2.3.0' > final OkHttpVersion = '3.9.1'

  1. Create an array of related dependency, so you can easily find it later. Add it in build.gradle (app level) outside of dependency block:

> // Using version in library and add dependency along with access > name(like retrofit(first one)) > > final networkDependencies = [ > retrofit : "com.squareup.retrofit2:retrofit:${RetrofitVersion}", > retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:${RetrofitVersion}", > retrofitRxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava2:${RetrofitVersion}", > okHttp3 : "com.squareup.okhttp3:okhttp:${OkHttpVersion}", > okHttp3Logging : "com.squareup.okhttp3:logging-interceptor:${OkHttpVersion}" > ]

  1. And in dependency block:

> // Implement all the dependency from array > > dependencies { > implementation fileTree(dir: 'libs', include: ['*.jar']) >
> implementation networkDependencies.values() > }


So the final code will look like this:

final RetrofitVersion = '2.3.0'
final OkHttpVersion = '3.9.1'

final networkDependencies = [
        retrofit             : "com.squareup.retrofit2:retrofit:${RetrofitVersion}",
        retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:${RetrofitVersion}",
        retrofitRxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava2:${RetrofitVersion}",
        okHttp3              : "com.squareup.okhttp3:okhttp:${OkHttpVersion}",
        okHttp3Logging       : "com.squareup.okhttp3:logging-interceptor:${OkHttpVersion}"
]

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation networkDependencies.values()
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStanislav BashkyrtsevView Question on Stackoverflow
Solution 1 - GradlePeter NiederwieserView Answer on Stackoverflow
Solution 2 - GradleAdrian BakerView Answer on Stackoverflow
Solution 3 - GradleroomsgView Answer on Stackoverflow
Solution 4 - GradlegavenkoaView Answer on Stackoverflow
Solution 5 - GradleUmeshsolankiView Answer on Stackoverflow
Solution 6 - GradledattaView Answer on Stackoverflow
Solution 7 - GradleDhaval JivaniView Answer on Stackoverflow
Solution 8 - GradletkruseView Answer on Stackoverflow
Solution 9 - GradleMahozadView Answer on Stackoverflow
Solution 10 - GradleSuraj VaishnavView Answer on Stackoverflow