Version catalogs

Gradle · Practical · 10 min

Catalogs keep versions consistent across subprojects and are the modern standard in Android and JVM builds.

A version catalog declares dependency coordinates and versions once, in gradle/libs.versions.toml, and every build script references them through the type-safe libs accessor.

[versions]
junit = "5.11.4"
kotlin = "2.1.20"

[libraries]
guava = { module = "com.google.guava:guava", version = "33.4.0-jre" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }

[bundles]
testing = ["junit-jupiter"]

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

Then implementation(libs.guava), testImplementation(libs.bundles.testing) and plugins { alias(libs.plugins.kotlin.jvm) }. Dashes in names become dots in accessors.

Benefits: one place to bump versions, IDE completion, no string typos, and tooling such as Renovate and Dependabot understands the file. version.ref shares a version among related artifacts (all Kotlin or all Jackson modules), and bundles group libraries that are always used together.

The catalog named libs is picked up automatically; additional catalogs can be declared in dependencyResolutionManagement { versionCatalogs { } } in settings.gradle.kts, or published as a .toml artifact for sharing across repositories.

Catalogs don't change resolution rules: they only provide coordinates. Use platforms/BOMs (implementation(platform(libs.spring.bom))) when you need to align transitive versions.

Example

# gradle/libs.versions.toml
[versions]
junit = "5.11.4"
jackson = "2.18.3"

[libraries]
guava = { module = "com.google.guava:guava", version = "33.4.0-jre" }
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
jackson-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }

[bundles]
jackson = ["jackson-databind", "jackson-kotlin"]

[plugins]
spring-boot = { id = "org.springframework.boot", version = "3.4.4" }

# build.gradle.kts
# plugins { alias(libs.plugins.spring.boot) }
# dependencies {
#     implementation(libs.guava)
#     implementation(libs.bundles.jackson)
#     testImplementation(libs.junit.jupiter)
# }

Remember

  • gradle/libs.versions.toml holds versions, libraries, bundles and plugins
  • Use libs.xxx accessors; dashes become dots
  • version.ref shares one version across related artifacts
  • Catalogs provide coordinates; BOMs/platforms align transitive versions

Check yourself

  1. How is a catalog library named junit-jupiter referenced in build.gradle.kts?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.gradle.org/current/userguide/version_catalogs.html