In modern Android and Kotlin Multiplatform development, managing dependencies across multiple modules can quickly become messy. Manually updating versions in each build.gradle.kts file is not only error-prone—it’s a headache when scaling projects.
That’s where libs.versions.toml steps in—the primary and recommended configuration file for Gradle Version Catalogs, a game-changing feature introduced in Gradle 7.0 and stabilized in 7.4.
In this in-depth guide, you’ll learn how to master libs.versions.toml—from setting it up, organizing your dependencies and plugins, to managing versions like a seasoned pro.
What is libs.versions.toml?
libs.versions.toml is a centralized configuration file introduced in Gradle 7+ that lets you declare and manage dependencies, plugin versions, and bundles in one place.
This improves:
- Readability of dependency definitions
- Consistency across modules
- Maintainability by updating versions in a single file
Enabling Version Catalogs
Before you can use libs.versions.toml, make sure you’re on Gradle 7.0+ and Kotlin DSL (.kts).
In your project’s settings.gradle.kts, enable the version catalog:
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("gradle/libs.versions.toml"))
}
}
}This tells Gradle to look for a libs.versions.toml file inside the gradle/ directory.
Creating libs.versions.toml
Create the file at:
project-root/
├── gradle/
│ └── libs.versions.tomlLet’s break down its structure.
Structure of the File
The file is divided into three main sections:
[versions]
[libraries]
[plugins]- [versions]: Define all your version numbers here.
- [libraries]: List your dependencies, referencing versions from above.
- [plugins]: List your plugins, referencing versions as well
Defining Versions
Under [versions], you define the reusable version strings.
[versions]
kotlin = "1.9.22"
agp = "8.4.0"
coroutines = "1.7.3"This creates version aliases. You can later reference these in your dependency and plugin definitions.
Adding Libraries
Under [libraries], you define the actual dependencies:
[libraries]
compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "compose" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }Or, use the module shorthand:
[libraries]
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version = "2.9.0" }Here, you define your dependencies using aliases. Reference the version from the [versions] block to keep things DRY (Don’t Repeat Yourself).
Explanation:
module= full Maven coordinateversion= direct versionversion.ref= refers to a shared version from[versions]
This improves consistency and avoids duplication.
Adding Plugins
Under [plugins], plugins are managed just like libraries. Reference the version from [versions] for consistency.
[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "agp" }Using the Version Catalog in Your Build Files
Once your libs.versions.toml is set up, you can use its entries in your module-level build.gradle.kts files.
Applying Plugins
Replace hardcoded plugin IDs and versions with aliases:
plugins {
alias(libs.plugins.kotlin.android)
}Adding Dependencies
Use the aliases you defined for dependencies:
dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.material3)
}Using Bundles (optional, but highly recommended for grouping related dependencies)
You can group related dependencies into bundles for convenience:
[bundles]
compose = [
"compose-ui",
"compose-material3"
]And use them in your build file:
dependencies {
implementation(libs.bundles.compose)
}It reduces boilerplate and enforces consistency.
Pro Tips for libs.versions.toml
1. Use Comments Wisely
Unlike JSON or YAML, .toml supports inline comments:
kotlin = "1.9.22" # Kotlin version used for both plugin and stdlibHelpful when collaborating or reviewing changes.
2. Semantic Grouping
Group dependencies logically: UI, Networking, Testing, etc.
[libraries]
# UI
compose-ui = { module = "androidx.compose.ui:ui", version = "1.6.2" }
compose-material = { module = "androidx.compose.material:material", version = "1.6.2" }
# Testing
junit = { module = "junit:junit", version = "4.13.2" }Improves navigation and scalability.
3. Version Locking & Conflict Resolution
If you use a dependency with a transitive mismatch, use constraints in build.gradle.kts:
dependencies {
implementation(libs.some.lib)
constraints {
implementation("some:transitive-lib:1.2.3")
}
}This ensures predictable builds.
Real-world Usage Example
libs.versions.toml:
[versions]
kotlin = "1.9.22"
agp = "8.4.0"
coroutines = "1.7.3"
compose = "1.6.2"
[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "agp" }
[bundles]
core = ["kotlin-stdlib", "coroutines-core"]app/build.gradle.kts:
plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.android.application)
}
dependencies {
implementation(libs.bundles.core)
implementation(libs.compose.ui)
}Simple, elegant, and maintainable.
Why libs.versions.toml Matters
As projects grow, consistency becomes critical. libs.versions.toml:
- Reduces version mismatches
- Makes updates seamless
- Keeps modules DRY (Don’t Repeat Yourself)
- Is IDE-friendly and fully supported by Android Studio
It’s the kind of practice that scales well in enterprise codebases and simplifies maintenance.
Conclusion
If you’re not using libs.versions.toml, now’s the time to start.
Whether you’re building a small Android app or managing dozens of modules across a large monorepo, version catalogs offer clarity, consistency, and control.
Keep your libs.versions.toml organized, document versions, and treat it like your project’s single source of truth.
