Adopt Gradle Version Catalogs to Centralize Dependency Coordinates in Multi‑Module Builds
Learn how a Gradle version catalog eliminates repeated dependency coordinates, improves maintainability, and works with Kotlin DSL.
17 Jan 2026, 05:48 UTC

Why a version catalog solves the repeat‑dependency problem
In a multi‑module Gradle build the same group:name:version strings often appear in many build.gradle.kts files. When a library version needs to be bumped, each occurrence must be edited manually, which is error‑prone and leads to version drift. A version catalog provides a single source of truth: the file gradle/libs.versions.toml lives at the repository root and stores every dependency and plugin coordinate once. All subprojects reference the catalog through the generated libs extension, so changing a version requires only one line edit.
How Gradle loads and exposes the catalog
Gradle automatically looks for gradle/libs.versions.toml in the root project. If the file exists, it creates a VersionCatalog object and makes it available as the libs extension on every project. For each alias defined in the TOML, Gradle generates a type‑safe accessor; dashes in the alias are converted to dots, so jackson-databind becomes libs.jackson.databind. This means you can write implementation(libs.jackson.databind) in any build.gradle.kts and Gradle will resolve the coordinate from the catalog at configuration time.
Worked TOML + Kotlin DSL example
[versions]
jackson = "2.17.1"
[libraries]
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
[bundles]
jackson = ["jackson-databind"]
[plugins]
spotless = { id = "com.diffplug.spotless", version = "6.25.0" }
dependencies {
implementation(libs.jackson.databind)
implementation(bundle(libs.jackson))
}
plugins {
alias(libs.plugins.spotless)
}
The TOML declares a version jackson and a library jackson-databind that references that version. A bundle groups the library under the name jackson, allowing implementation(bundle(libs.jackson)) to add all members of the bundle. The plugin alias spotless is applied with alias(libs.plugins.spotless) in the plugins block.
Beyond the default file: publishing and importing catalogs
Teams that want to share a catalog across multiple repositories can publish it with the version-catalog plugin. The published artifact is consumed in settings.gradle.kts via dependencyResolutionManagement.versionCatalogs { create("libs") { from("group:artifact:version") } }. This centralises dependency policy at an organisational level while still giving each build the same type‑safe accessors.
Limits of the catalog approach
- Alias keys may contain only lowercase letters, digits, dashes, underscores and dots; dashes are turned into dots in the generated accessor (
my-lib→libs.my.lib). - The catalog stores coordinates only; it does not enforce a single version across transitive dependencies. If two libraries pull different versions of the same module, Gradle will still resolve a conflict unless you add a platform, BOM or explicit dependency constraints.
- Catalog entries are static manifests; they do not automatically upgrade when a newer version is released.
Common mistakes to avoid
- Keeping hardcoded
group:name:versionstrings in some modules while using the catalog elsewhere – this re‑introduces drift. - Assuming the catalog will align versions automatically; treat it as a lookup table, not a version‑enforcement mechanism.
- Creating aliases that clash with generated accessor names (e.g., an alias named
libsshadows the extension). - Trying to use version catalogs on Gradle releases older than 7.0; the feature was incubating in early 7.x and became stable with Gradle 7.4.
Practical verification steps
- Confirm you are on a supported Gradle version: run
gradle --versionand ensure the output shows 7.4 or higher. - From the project root, execute
./gradlew dependencies --configuration runtimeClasspath(orgradle dependenciesif you use the wrapper). Inspect the output for the library you added via the catalog; the resolved version should match the value defined ingradle/libs.versions.toml. - Open the project in IntelliJ IDEA (or another IDE with Gradle support). After the Gradle sync finishes, type
libs.in anybuild.gradle.ktsfile and verify that code completion shows the accessors you defined (e.g.,jackson.databind,jackson,plugins.spotless). - To check that the catalog is truly the source of truth, temporarily change the version in the TOML (e.g., bump
jacksonto2.18.0), reload the Gradle project, and repeat thedependenciestask. The resolved version should update accordingly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.