Mastering libs.versions.toml: Add Plugins, Dependencies & Manage Versions Like a Pro

Table of Contents

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:

Kotlin
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:

Kotlin
project-root/
├── gradle/
│   └── libs.versions.toml

Let’s break down its structure.

Structure of the File

The file is divided into three main sections:

Kotlin
[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.

Kotlin
[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:

Kotlin
[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:

Kotlin
[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 coordinate
  • version = direct version
  • version.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.

Kotlin
[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:

Kotlin
plugins {
    alias(libs.plugins.kotlin.android)
}

Adding Dependencies

Use the aliases you defined for dependencies:

Kotlin
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:

Kotlin
[bundles]
compose = [
    "compose-ui",
    "compose-material3"
]

And use them in your build file:

Kotlin
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
kotlin = "1.9.22" # Kotlin version used for both plugin and stdlib

Helpful when collaborating or reviewing changes.

2. Semantic Grouping

Group dependencies logically: UI, Networking, Testing, etc.

Kotlin
[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:

Kotlin
dependencies {
    implementation(libs.some.lib)
    constraints {
        implementation("some:transitive-lib:1.2.3")
    }
}

This ensures predictable builds.

Real-world Usage Example

libs.versions.toml:

Kotlin
[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:

Kotlin
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.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!