# Using Catalogs with Platforms

version 8.14.4-20251227040319+0000

Both platforms and version catalogs help manage dependency versions in a project, but they serve different purposes and have different effects on dependency resolution:

## Version Catalogs

- Purpose: A version catalog centralizes and standardizes dependency coordinates (group, name, version) and provides type-safe accessors in the build script, making dependencies easier to manage.

- Effect on Dependency Graph: Version catalogs do not directly affect dependency resolution. The versions defined in the catalog must be explicitly referenced in a `dependencies` block, and once referenced, they behave the same as any locally declared dependency. Additionally, the catalog’s contents are transparent to downstream consumers, meaning that consumers cannot identify whether a dependency was declared locally or sourced from a catalog.

libs.versions.toml

    [libraries]
    mylib = { group = "com.example", name = "mylib", version = "1.0.0" }

## Platforms

- Purpose: A platform is a module in the dependency graph that enforces or aligns versions of dependencies (including transitive dependencies). It influences dependency resolution and ensures version consistency across different modules.

- Effect on Dependency Graph: Platforms apply or enforce versions to dependencies that are declarated locally without versions. These versions in a platform are propagated through the dependency graph, affecting transitive dependencies and downstream consumers. They are a formal part of the dependency graph and can dictate the version chosen during resolution.

build.gradle.kts

    plugins {
        `java-platform`
    }

    dependencies {
        constraints {
            api("com.example:mylib:2.0.0")
        }
    }

## Using a catalog with a platform

Even if a version catalog defines a version for a dependency, Gradle might pick a different version during resolution if another component (e.g., a platform or a transitive dependency) suggests a different version (unless `enforcedPlatform` is used).

For example, a version catalog may define `mylib` as version `1.0.0`, but if a platform enforces `2.0.0`, Gradle will select version `2.0.0`.

To ensure consistent version alignment, a good approach is to use a version catalog to define dependency versions alongside a platform to enforce them.

Version Catalog:

gradle/libs.versions.toml

    [versions]
    junit-jupiter = "5.10.3"

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

Platform:

platform/build.gradle.kts

    plugins {
        `java-platform`
    }

    javaPlatform {
        allowDependencies()
    }

    dependencies {
        constraints {
            api("org.junit.jupiter:junit-jupiter:5.11.1") // Enforcing specific version
            api("com.google.guava:guava:[33.1.0-jre,)") // Enforcing version range
        }
    }

platform/build.gradle

    plugins {
        id 'java-platform'
    }

    javaPlatform {
        allowDependencies()
    }

    dependencies {
        constraints {
            api 'org.junit.jupiter:junit-jupiter:5.11.1' // Enforcing specific version
            api 'com.google.guava:guava:[33.1.0-jre,)' // Enforcing version range
        }
    }

Consumer:

consumer/build.gradle.kts

    dependencies {
        // Platform
        implementation(platform(project(":platform")))
        // Catalog
        testImplementation(libs.junit.jupiter)
        testRuntimeOnly(libs.junit.jupiter.launcher)
        implementation(libs.guava)
    }

consumer/build.gradle

    dependencies {
        // Platform
        implementation platform(project(":platform"))
        // Catalog
        testImplementation libs.junit.jupiter
        testRuntimeOnly libs.junit.jupiter.launcher
        implementation libs.guava
    }

Best Practices for using both a catalog and a platform:

1. Use version catalogs for defining and sharing dependency coordinates across projects. They make dependency declarations consistent and easier to manage but do not guarantee version alignment.

2. Use platforms when you need to influence or enforce version alignment across modules. Platforms ensure that dependencies resolve to the desired version, particularly in large or multi-module projects.