How do you publish a version catalog so other builds can import it, and how does the consuming build pull it in?
answer
- producer: version-catalog + maven-publish plugins
- catalog { versionCatalog { from(files()) } }
- from(components["versionCatalog"]) → @toml artifact
- consumer: from("g:a:v") in settings
- repos in dependencyResolutionManagement
basics
~20 sIn a producer project apply the version-catalog plugin, define entries via the catalog { versionCatalog { ... } } extension, and publish with maven-publish (the catalog adds a versionCatalog component). Consumers import it via from("group:artifact:version") in settings.
solid answer
~40 sTo share a catalog *across builds* you publish it as an artifact. In a dedicated producer project apply the **`version-catalog`** plugin; it adds a `catalog` extension where you populate entries — either `catalog { versionCatalog { from(files("libs.versions.toml")) } }` to base it on a TOML file, or with `library`/`version`/`bundle` builder calls. The plugin creates a `versionCatalog` software component and a `generateCatalogAsToml` task; apply `maven-publish` and add a publication `from(components["versionCatalog"])` to push a `*.toml` artifact with `@toml` packaging to your repository. Consuming builds then do, in `settings.gradle.kts`, `dependencyResolutionManagement { versionCatalogs { create("sharedLibs") { from("com.acme:my-catalog:1.0") } } }`. The resolved TOML becomes a normal catalog with type-safe accessors (`sharedLibs.guava`). This decouples version governance from individual repos.
code
kotlin · 17 lines// PRODUCER build.gradle.kts
plugins { `version-catalog`; `maven-publish` }
catalog { versionCatalog { from(files("libs.versions.toml")) } }
publishing {
publications {
create<MavenPublication>("catalog") {
groupId = "com.acme"; artifactId = "my-catalog"; version = "1.0"
from(components["versionCatalog"])
}
}
}
// CONSUMER settings.gradle.kts
dependencyResolutionManagement {
repositories { maven { url = uri("https://repo.acme.com") } }
versionCatalogs { create("sharedLibs") { from("com.acme:my-catalog:1.0") } }
}go deeper
Awareness that catalogs can be published and imported across builds.
Know the producer needs version-catalog + maven-publish and the consumer uses from("g:a:v").
Wire the versionCatalog component into a publication and configure consumer repositories correctly; explain the @toml artifact.
Design org-wide catalog publishing/versioning as governance, including rollout strategy and the catalog-vs-platform distinction.
## The problem it solves A single `gradle/libs.versions.toml` is shared only *within one build*. Across many independent repositories you want **one** governed catalog. The `version-catalog` plugin turns a catalog into a **publishable artifact** so every team imports the same versions. ## Producer side: the `version-catalog` plugin Apply it in a standalone project: ```kotlin plugins { `version-catalog` `maven-publish` } catalog { versionCatalog { from(files("libs.versions.toml")) // or build entries programmatically: // version("guava", "33.0.0-jre") // library("guava", "com.google.guava", "guava").versionRef("guava") } } publishing { publications { create<MavenPublication>("catalog") { groupId = "com.acme" artifactId = "my-catalog" version = "1.0" from(components["versionCatalog"]) } } } ``` Key pieces: - The `catalog` **extension** (from the plugin) exposes `versionCatalog { ... }`, the same builder API as the settings DSL — `from(files(...))`, `version`, `library`, `bundle`, `plugin`. - The plugin registers a **`versionCatalog` component** and a `generateCatalogAsToml` task that emits the `.toml`. - `from(components["versionCatalog"])` wires that component into a Maven publication. The published module has packaging/extension **`toml`** and dependency type `version-catalog`. ## Consumer side: importing the published catalog In the consuming build's `settings.gradle.kts`: ```kotlin dependencyResolutionManagement { repositories { mavenCentral(); maven { url = uri("https://repo.acme.com") } } versionCatalogs { create("sharedLibs") { from("com.acme:my-catalog:1.0") } } } ``` The dependency-notation `from("g:a:v")` resolves the published catalog (its repositories come from `dependencyResolutionManagement.repositories`, the settings-level resolution context). Entries become accessors under the catalog name you chose (`sharedLibs.*`). ## Architectural notes - Choose the **catalog name** in the consumer (`create("sharedLibs")`); it need not match the producer's artifact id. - Version the catalog artifact like any library; consumers bump it deliberately, giving you a controlled rollout of dependency upgrades org-wide. - A published catalog is *just versions/coordinates* — it does not force resolution; modules still opt in by referencing accessors. Pair it with a published **platform** (BOM) if you need to *enforce* versions, which is a separate mechanism. ## Common gotchas - The plugin id is `version-catalog` (not `versions`); the producer is a normal project, **not** the settings file. - Consumers must declare the **repository** that hosts the artifact in settings-level `dependencyResolutionManagement.repositories`, or resolution of `from("g:a:v")` fails.
- Why must the consumer declare repositories inside `dependencyResolutionManagement` rather than in a build script?`from("g:a:v")` resolves at the settings level before any project is configured, so it uses the settings-level `dependencyResolutionManagement.repositories`. A project's `repositories {}` block is not yet available when the catalog is imported.
- Does importing a published catalog force every module onto those versions?No. A catalog only supplies coordinates/versions for declarations you opt into via accessors. To *enforce* versions transitively you need a platform/BOM, which is a different mechanism.
- Where is the `version-catalog` plugin applied — settings or a project?A regular project (the producer), where it adds the `catalog` extension and `versionCatalog` component for `maven-publish`. The settings file is only involved on the consuming side.
saying these in an interview costs you the question
- Applying the `version-catalog` plugin in settings.gradle.kts — it belongs in a producer project.
- Forgetting to declare the hosting repository on the consumer side, then blaming the catalog.
- Claiming a published catalog enforces versions like a BOM.