Centralize Gradle Dependencies with Version Catalogs (TOML)
Declare all dependency coordinates once in gradle/libs.versions.toml, then reference them via type‑safe libs.* accessors in Kotlin DSL. This guide covers setup, verification, and recovery for multi‑project builds.
23 Nov 2025, 12:23 UTC

Problem and Takeaway
Managing dependency coordinates across multiple Gradle subprojects leads to version drift, duplication, and fragile builds. Gradle Version Catalogs solve this by declaring every group, artifact, and version once in a gradle/libs.versions.toml file, then referencing them via type‑safe libs.* accessors in Kotlin DSL scripts. The result: consistent versions, IDE auto‑completion, and a single source of truth for all modules.
Prerequisites
- Gradle 7.4 or later (8.5+ recommended; version catalogs are stable from 8.0).
- A multi‑project build or a single project using Kotlin DSL (
build.gradle.kts). - Wrapper updated to a supported version: run
./gradlew wrapper --gradle-version 8.5from the project root (requires execute permission ongradlew). - If on Gradle 7.x, enable the feature preview in
settings.gradle.kts:
This call is deprecated in 8.0+ and can be omitted.enableFeaturePreview("VERSION_CATALOGS")
Procedure
1. Create the catalog file
Add gradle/libs.versions.toml at the root of your build (next to settings.gradle.kts). Use four sections: [versions], [libraries], [plugins], and [bundles].
# gradle/libs.versions.toml
[versions]
kotlin = "1.9.20"
agp = "8.2.0"
[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "agp" }
[bundles]
kotlin = ["kotlin-stdlib", "kotlin-reflect"]
Each library entry points to a version reference, so updating kotlin in [versions] propagates everywhere.
2. Configure plugin repositories
In settings.gradle.kts, ensure the plugin management block resolves plugins from the Gradle Plugin Portal and Maven Central:
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
3. Apply plugins and dependencies in subprojects
In each build.gradle.kts, use the generated accessors:
// subproject/build.gradle.kts
plugins {
alias(libs.plugins.kotlin.jvm)
// alias(libs.plugins.android.application) // for Android modules
}
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.bundles.kotlin) // expands to both stdlib and reflect
}
IntelliJ IDEA 2023.2+ provides code completion for libs. as you type.
Expected Checks
- Verify resolved versions – run from the project root:
Confirm that./gradlew :app:dependencies --configuration compileClasspathkotlin-stdlibresolves to1.9.20(or whatever version you declared). - Inspect a single dependency:
The output should show the version originating from the catalog entry../gradlew :app:dependencyInsight --dependency kotlin-stdlib - IDE completion – open a
.ktsfile, typelibs.and verify suggestions match your TOML keys. - Build scan (optional) – execute
./gradlew build --scanand check the “Dependencies” tab for catalog‑sourced entries.
Recovery Options
- Catalog sync failures – delete the
.gradlecaches (rm -rf .gradle) and re‑import the project in the IDE. - Version conflicts – add a resolution strategy in
settings.gradle.kts:dependencyResolutionManagement { resolutionStrategy { force(libs.kotlin.stdlib) } } - TOML syntax errors – run
./gradlew :help --task :dependencies; Gradle fails fast and reports the line number. - Rollback – revert
gradle/libs.versions.tomlto the previous version and run./gradlew --refresh-dependencies.
Advanced: Sharing Catalogs Across Builds
To reuse a catalog from a shared location (e.g., a platform repository), reference it in settings.gradle.kts:
versionCatalogs {
create("libs") {
from(files("../shared/gradle/libs.versions.toml"))
}
}
For organization‑wide distribution, publish the catalog as a Maven artifact using the maven-publish plugin and consume it via from(maven("com.myorg:gradle-catalog:1.0")).
Limitations and Verification
- Catalogs are immutable at configuration time; changing a version requires a Gradle reload (IDE re‑import or
./gradlew --refresh-dependencies). - Mixing catalog references with legacy
extordependencies {}blocks for the same coordinates causes confusion – pick one approach per project. - Plugin aliases via
alias(libs.plugins.foo)work only in Kotlin DSL. Groovy DSL usesplugins { alias(libs.plugins.foo) }but lacks type‑safe accessors. - Practical verification: after any catalog edit, run
./gradlew :subproject:dependencyInsight --dependency <artifact>and confirm the version matches the TOML entry.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.