# Version Catalogs

version 9.0.0

A version catalog is a selected list of dependencies that can be referenced in build scripts, simplifying dependency management.

Instead of specifying dependencies directly using string notation, you can pick them from a version catalog:

build.gradle.kts

    dependencies {
        implementation(libs.groovy.core)
    }

build.gradle

    dependencies {
        implementation(libs.groovy.core)
    }

In this example, `libs` represents the catalog, and `groovy` is a dependency available in it.

Where the version catalog defining `libs.groovy.core` is a `libs.versions.toml` file in the `gradle` directory:

gradle/libs.versions.toml

    [libraries]
    groovy-core = { group = "org.codehaus.groovy", name = "groovy", version = "3.0.5" }

Version catalogs offer several advantages:

- Type-Safe Accessors: Gradle generates type-safe accessors for each catalog, enabling autocompletion in IDEs.

- Centralized Version Management: Each catalog is visible to all projects in a build.

- Dependency Bundles: Catalogs can group commonly used dependencies into bundles.

- Version Separation: Catalogs can separate dependency coordinates from version information, allowing shared version declarations.

- Conflict Resolution: Like regular dependency notation, version catalogs declare requested versions but do not enforce them during conflict resolution.

While version catalogs define versions, they don’t influence the dependency resolution process. Gradle may still select different versions due to dependency graph conflicts or constraints applied through platforms or dependency management APIs.

| Versions declared in a catalog are typically not enforced, meaning the actual version used in the build may differ based on dependency resolution.

## Accessing a catalog

To access items in a version catalog defined in the standard `libs.versions.toml` file located in the `gradle` directory, you use the `libs` object in your build scripts. For example, to reference a library, you can use `libs.<alias>`, and for a plugin, you can use `libs.plugins.<alias>`.

Declaring dependencies using a version catalog:

build.gradle.kts

    dependencies {
        implementation(libs.groovy.core)
        implementation(libs.groovy.json)
        implementation(libs.groovy.nio)
    }

build.gradle

    dependencies {
        implementation libs.groovy.core
        implementation libs.groovy.json
        implementation libs.groovy.nio
    }

Is the same as:

build.gradle.kts

    dependencies {
        implementation("org.codehaus.groovy:groovy:3.0.5")
        implementation("org.codehaus.groovy:groovy-json:3.0.5")
        implementation("org.codehaus.groovy:groovy-nio:3.0.5")
    }

build.gradle

    dependencies {
        implementation 'org.codehaus.groovy:groovy:3.0.5'
        implementation 'org.codehaus.groovy:groovy-json:3.0.5'
        implementation 'org.codehaus.groovy:groovy-nio:3.0.5'
    }

Accessors map directly to the aliases and versions defined in the TOML file, offering type-safe access to dependencies and plugins. This enables IDEs to provide autocompletion, highlight typos, and identify missing dependencies as errors.

### Aliases and type-safe accessors

Aliases in a version catalog consist of identifiers separated by a dash (`-`), underscore (`_`), or dot (`.`). Type-safe accessors are generated for each alias, normalized to dot notation:

Example aliases | Generated accessors
--- | ---
`guava` | `libs.guava`
`groovy-core` | `libs.groovy.core`
`androidx.awesome.lib` | `libs.androidx.awesome.lib`

## Creating a catalog

Version catalogs are conventionally declared using a `libs.versions.toml` file located in the `gradle` subdirectory of the root build:

gradle/libs.versions.toml

    [versions]
    groovy = "3.0.5"
    checkstyle = "8.37"

    [libraries]
    groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
    groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
    groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
    commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }

    [bundles]
    groovy = ["groovy-core", "groovy-json", "groovy-nio"]

    [plugins]
    versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }

### The TOML catalog format

The TOML file has four sections:

- `[versions]` – Declares version identifiers.

- `[libraries]` – Maps aliases to GAV coordinates.

- `[bundles]` – Defines dependency bundles.

- `[plugins]` – Declares plugin versions.

The TOML file format is very lenient and lets you write "dotted" properties as shortcuts to full object declarations.

#### Versions

Versions can be declared either as a single string, in which case they are interpreted as a required version, or as a rich version:

    [versions]
    other-lib = "5.5.0" # Required version
    my-lib = { strictly = "[1.0, 2.0[", prefer = "1.2" } # Rich version

Supported members of a version declaration are:

- `require`: the required version

- `strictly`: the strict version

- `prefer`: the preferred version

- `reject`: the list of rejected versions

- `rejectAll`: a boolean to reject all versions

#### Libraries

Each library is mapped to a GAV coordinate: group, artifact, version. They can be declared as a simple string, in which case they are interpreted coordinates, or separate group and name:

    [versions]
    common = "1.4"

    [libraries]
    my-lib = "com.mycompany:mylib:1.4"
    my-lib-no-version.module = "com.mycompany:mylib"
    my-other-lib = { module = "com.mycompany:other", version = "1.4" }
    my-other-lib2 = { group = "com.mycompany", name = "alternate", version = "1.4" }
    mylib-full-format = { group = "com.mycompany", name = "alternate", version = { require = "1.4" } }

    [plugins]
    short-notation = "some.plugin.id:1.4"
    long-notation = { id = "some.plugin.id", version = "1.4" }
    reference-notation = { id = "some.plugin.id", version.ref = "common" }

You can also define strict or preferred versions using `strictly` or `prefer`:

    [libraries]
    commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer = "3.9" } }

In case you want to reference a version declared in the `[versions]` section, use the `version.ref` property:

    [versions]
    some = "1.4"

    [libraries]
    my-lib = { group = "com.mycompany", name="mylib", version.ref="some" }

#### Bundles

Bundles group multiple library aliases, so they can be referenced together in the build script.

    [versions]
    groovy = "3.0.9"

    [libraries]
    groovy-core = { group = "org.codehaus.groovy", name = "groovy", version.ref = "groovy" }
    groovy-json = { group = "org.codehaus.groovy", name = "groovy-json", version.ref = "groovy" }
    groovy-nio = { group = "org.codehaus.groovy", name = "groovy-nio", version.ref = "groovy" }

    [bundles]
    groovy = ["groovy-core", "groovy-json", "groovy-nio"]

This is useful for pulling in several related dependencies with a single alias:

build.gradle.kts

    dependencies {
        implementation(libs.bundles.groovy)
    }

build.gradle

    dependencies {
        implementation libs.bundles.groovy
    }

#### Plugins

This section defines the plugins and their versions by mapping plugin IDs to version numbers. Just like libraries, you can define plugin versions using aliases from the `[versions]` section or directly specify the version.

    [plugins]
    versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }

Which can be accessed in any project of the build using the `plugins {}` block. To refer to a plugin from the catalog, use the `alias()` function:

build.gradle.kts

    plugins {
        `java-library`
        checkstyle
        alias(libs.plugins.versions)
    }

build.gradle

    plugins {
        id 'java-library'
        id 'checkstyle'
        // Use the plugin `versions` as declared in the `libs` version catalog
        alias(libs.plugins.versions)
    }

| You cannot use a plugin declared in a version catalog in your settings file or settings plugin.

### Avoiding subgroup accessors

To avoid generating subgroup accessors, use camelCase notation:

Aliases | Accessors
--- | ---
`groovyCore` | `libs.groovyCore`
`groovyJson-core` | `libs.groovyJson.core`

### Reserved keywords

Certain keywords, like `extensions`, `class`, and `convention`, are reserved and cannot be used as aliases. Additionally, `bundles`, `versions`, and `plugins` cannot be the first subgroup in a dependency alias.

For example, the alias `versions-dependency` is not valid, but `versionsDependency` or `dependency-versions` are valid.

## Publishing a catalog

In most cases, the `gradle/libs.versions.toml` will be checked into a repository and available for consumption.

However, this doesn’t always solve the problem of sharing a catalog in an organization or for external consumers. Another option to share a catalog is to write a settings plugin, publish it on the Gradle plugin portal or an internal repository, and let the consumers apply the plugin on their settings file.

Alternatively, Gradle offers a version catalog plugin, which has the ability to declare and publish a catalog.

To do this, you need to apply the `version-catalog` plugin:

build.gradle.kts

    plugins {
        `version-catalog`
        `maven-publish`
    }

build.gradle

    plugins {
        id 'version-catalog'
        id 'maven-publish'
    }

This plugin will then expose the catalog extension that you can use to declare a catalog:

build.gradle.kts

    catalog {
        // declare the aliases, bundles and versions in this block
        versionCatalog {
            library("my-lib", "com.mycompany:mylib:1.2")
        }
    }

build.gradle

    catalog {
        // declare the aliases, bundles and versions in this block
        versionCatalog {
            library('my-lib', 'com.mycompany:mylib:1.2')
        }
    }

The plugin must be created programmatically, see Programming catalogs for details.

Such a catalog can then be published by applying either the `maven-publish` or `ivy-publish` plugin and configuring the publication to use the `versionCatalog` component:

build.gradle.kts

    publishing {
        publications {
            create<MavenPublication>("maven") {
                from(components["versionCatalog"])
            }
        }
    }

build.gradle

    publishing {
        publications {
            maven(MavenPublication) {
                from components.versionCatalog
            }
        }
    }

When publishing such a project, a `libs.versions.toml` file will automatically be generated (and uploaded), which can then be consumed from other Gradle builds.

## Importing a published catalog

A catalog produced by the Version Catalog Plugin can be imported via the Settings API:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                from("com.mycompany:catalog:1.0")
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                from("com.mycompany:catalog:1.0")
            }
        }
    }

## Importing a catalog from a file

| Gradle automatically imports a catalog in the `gradle` directory named `libs.versions.toml`.

The version catalog builder API allows importing a catalog from an external file, enabling reuse across different parts of a build, such as sharing the main build’s catalog with `buildSrc`.

For example, you can include a catalog in the `buildSrc/settings.gradle(.kts)` file as follows:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                from(files("../gradle/libs.versions.toml"))
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                from(files("../gradle/libs.versions.toml"))
            }
        }
    }

The VersionCatalogBuilder.from(Object dependencyNotation) method accepts only a single file, meaning that notations like Project.files(java.lang.Object…​) must refer to one file. Otherwise, the build will fail.

| Remember that you don’t need to import the version catalog named `libs.versions.toml` if it resides in your `gradle` folder. It will be imported automatically.

However, if you need to import version catalogs from multiple files, it’s recommended to use a code-based approach instead of relying on TOML files. This approach allows for the declaration of multiple catalogs from different files:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            // declares an additional catalog, named 'testLibs', from the 'test-libs.versions.toml' file
            create("testLibs") {
                from(files("gradle/test-libs.versions.toml"))
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            // declares an additional catalog, named 'testLibs', from the 'test-libs.versions.toml' file
            testLibs {
                from(files('gradle/test-libs.versions.toml'))
            }
        }
    }

## Importing multiple catalogs

You can declare multiple catalogs to organize dependencies better by using the Settings API:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                from(files("gradle/libs.versions.toml"))
            }
            create("tools") {
                from(files("gradle/tools.versions.toml"))
            }
        }
    }

build.gradle.kts

    dependencies {
        implementation(libs.someDependency)
        implementation(tools.someTool)
    }

| To minimize the risk of naming conflicts, each catalog generates an extension applied to all projects, so it’s advisable to choose a unique name. One effective approach is to select a name that ends with `Libs`.

## Changing the catalog name

By default, the `libs.versions.toml` file is used as input for the `libs` catalog. However, you can rename the default catalog if an extension with the same name already exists:

settings.gradle.kts

    dependencyResolutionManagement {
        defaultLibrariesExtensionName = "projectLibs"
    }

settings.gradle

    dependencyResolutionManagement {
        defaultLibrariesExtensionName = 'projectLibs'
    }

## Overwriting catalog versions

You can overwrite versions when importing a catalog:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("amendedLibs") {
                from("com.mycompany:catalog:1.0")
                // overwrite the "groovy" version declared in the imported catalog
                version("groovy", "3.0.6")
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            amendedLibs {
                from("com.mycompany:catalog:1.0")
                // overwrite the "groovy" version declared in the imported catalog
                version("groovy", "3.0.6")
            }
        }
    }

In the examples above, any dependency referencing the `groovy` version will automatically be updated to use `3.0.6`.

| Overwriting a version only affects what is imported and used when declaring dependencies. The actual resolved dependency version may differ due to conflict resolution.

## Programming catalogs

Version catalogs can be declared programmatically in the `settings.gradle(.kts)` file.

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                version("groovy", "3.0.5")
                version("checkstyle", "8.37")
                library("groovy-core", "org.codehaus.groovy", "groovy").versionRef("groovy")
                library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")
                library("groovy-nio", "org.codehaus.groovy", "groovy-nio").versionRef("groovy")
                library("commons-lang3", "org.apache.commons", "commons-lang3").version {
                    strictly("[3.8, 4.0[")
                    prefer("3.9")
                }
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                version('groovy', '3.0.5')
                version('checkstyle', '8.37')
                library('groovy-core', 'org.codehaus.groovy', 'groovy').versionRef('groovy')
                library('groovy-json', 'org.codehaus.groovy', 'groovy-json').versionRef('groovy')
                library('groovy-nio', 'org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
                library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                    strictly '[3.8, 4.0['
                    prefer '3.9'
                }
            }
        }
    }

| Don’t use `libs` for your programmatic version catalog name if you have the default `libs.versions.toml` in your project.

Creating a version catalog programmatically uses the Settings API:

settings.gradle.kts

    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                version("groovy", "3.0.5")
                version("checkstyle", "8.37")
                library("groovy-core", "org.codehaus.groovy", "groovy").versionRef("groovy")
                library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")
                library("groovy-nio", "org.codehaus.groovy", "groovy-nio").versionRef("groovy")
                library("commons-lang3", "org.apache.commons", "commons-lang3").version {
                    strictly("[3.8, 4.0[")
                    prefer("3.9")
                }
                bundle("groovy", listOf("groovy-core", "groovy-json", "groovy-nio"))
            }
        }
    }

settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                version('groovy', '3.0.5')
                version('checkstyle', '8.37')
                library('groovy-core', 'org.codehaus.groovy', 'groovy').versionRef('groovy')
                library('groovy-json', 'org.codehaus.groovy', 'groovy-json').versionRef('groovy')
                library('groovy-nio', 'org.codehaus.groovy', 'groovy-nio').versionRef('groovy')
                library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                    strictly '[3.8, 4.0['
                    prefer '3.9'
                }
                bundle('groovy', ['groovy-core', 'groovy-json', 'groovy-nio'])
            }
        }
    }

## Using a catalog in `buildSrc`

Version catalogs provide a centralized way to manage dependencies in a project. However, `buildSrc` does not automatically inherit the version catalog from the main project, so additional configuration is required.

To access a version catalog inside `buildSrc`, you need to explicitly import it in `buildSrc/settings.gradle(.kts)`:

buildSrc/settings.gradle.kts

    // Add the version catalog to buildSrc using dependencyResolutionManagement
    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                from(files("../gradle/libs.versions.toml"))
            }
        }
    }

buildSrc/settings.gradle

    // Add the version catalog to buildSrc using dependencyResolutionManagement
    dependencyResolutionManagement {
        versionCatalogs {
            create("libs") {
                from(files("../gradle/libs.versions.toml"))
            }
        }
    }

Once the version catalog is imported, dependencies can be referenced using a few tricks:

buildSrc/build.gradle.kts

    plugins {
        `kotlin-dsl`
        alias(libs.plugins.versions) // Access version catalog in builSrc build file for plugin
    }

    repositories {
        gradlePluginPortal()
    }

    dependencies {
        // Access version catalog in buildSrc build file for dependencies
        implementation(plugin(libs.plugins.jacocolog)) // Plugin dependency
        implementation(libs.groovy.core) // Regular library from version catalog
        implementation("org.apache.commons:commons-lang3:3.9") // Direct dependency
    }

    // Helper function that transforms a Gradle Plugin alias from a
    // Version Catalog into a valid dependency notation for buildSrc
    fun DependencyHandlerScope.plugin(plugin: Provider<PluginDependency>) =
        plugin.map { "${it.pluginId}:${it.pluginId}.gradle.plugin:${it.version}" }

buildSrc/build.gradle

    plugins {
        id 'groovy-gradle-plugin'
        alias(libs.plugins.versions) // Access version catalog in buildSrc for plugin
    }

    repositories {
        gradlePluginPortal()
    }

    def catalogs = project.extensions.getByType(VersionCatalogsExtension)
    def libs = catalogs.named("libs")

    dependencies {
        // Access version catalog in buildSrc for dependencies
        implementation plugin(libs.findPlugin("jacocolog").get()) // Plugin dependency
        implementation libs.findLibrary("groovy-core").get() // Regular library from version catalog
        implementation "org.apache.commons:commons-lang3:3.9" // Direct dependency
    }

    // Helper function that transforms a Gradle Plugin alias from a
    // Version Catalog into a valid dependency notation for buildSrc
    def plugin(Provider<PluginDependency> plugin) {
        return plugin.map { it.pluginId + ":" + it.pluginId + ".gradle.plugin:" + it.version }
    }

In precompiled script plugins inside `buildSrc`, the version catalog can be accessed using `extensions.getByType(VersionCatalogsExtension)` as demonstrated in the dependencies block of this convention plugin:

buildSrc/src/main/kotlin/java-commons-convention.gradle.kts

    plugins {
        id("java-library")

        //alias(libs.plugins.jacocolog) // Unfortunately it is not possible the version catalog in buildSrc code for plugins

        // Remember that unlike regular Gradle projects, convention plugins in buildSrc do not automatically resolve
        // external plugins. We must declare them as dependencies in buildSrc/build.gradle.kts.
        id("org.barfuin.gradle.jacocolog") // Apply the plugin manually as a workaround with the external plugin
                                           // version from the version catalog specified in implementation dependency
                                           // artifact in build file
    }

    repositories {
        mavenCentral()
    }

    // Access the version catalog
    val libs = extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
    //val libs = the<VersionCatalogsExtension>().named("libs")

    dependencies {
        // Access version catalog in buildSrc code for dependencies
        implementation(libs.findLibrary("guava").get()) // Regular library from version catalog
        testImplementation(platform("org.junit:junit-bom:5.9.1")) // Platform dependency
        testImplementation("org.junit.jupiter:junit-jupiter") // Direct dependency
    }

    tasks.test {
        useJUnitPlatform()
    }

buildSrc/src/main/groovy/java-commons-convention.gradle

    plugins {
        id 'java-library'

        // alias(libs.plugins.jacocolog) - Unfortunately, it is not possible to use the version catalog for plugins in buildSrc

        // Unlike regular Gradle projects, convention plugins in buildSrc do not automatically resolve
        // external plugins. We must declare them as dependencies in buildSrc/build.gradle.
        id 'org.barfuin.gradle.jacocolog' // Apply the plugin manually as a workaround
        // The external plugin version comes from the implementation dependency
        // artifact in the build file
    }

    repositories {
        mavenCentral()
    }

    // Access the version catalog
    def libs = project.extensions.getByType(VersionCatalogsExtension).named("libs")

    dependencies {
        // Access version catalog in buildSrc for dependencies
        implementation libs.findLibrary("guava").get() // Regular library from version catalog
        testImplementation platform("org.junit:junit-bom:5.9.1") // Platform dependency
        testImplementation "org.junit.jupiter:junit-jupiter" // Direct dependency
    }

    tasks.withType(Test).configureEach {
        useJUnitPlatform()
    }

However, the plugins block in the precompiled script plugin cannot access the version catalog.