skip to content

Declaring and Sharing Catalogs

Declaring catalogs in dependencyResolutionManagement and publishing one with the version-catalog plugin so several builds share a single source of versions. Asked of anyone maintaining more than one repository in an organization.

on this pageshow

questions

5

What is a Gradle version catalog and where does the default `libs` catalog come from?

level: juniorimportance: must knowfreq 68%

answer

  1. central typed registry of coordinates
  2. auto `libs` from gradle/libs.versions.toml
  3. file base name = catalog name
  4. declared in settings, build-wide
  5. type-safe accessors libs.*

basics

~10 s

A version catalog is a central, typed list of dependency coordinates and versions shared across a build. Gradle auto-creates the libs catalog from gradle/libs.versions.toml if that file exists.

solid answer

~40 s

A version catalog is a single source of truth for dependency coordinates, versions, and bundles, shared by every project in a build so modules stop hard-coding `group:name:version` strings. Gradle gives you one catalog out of the box: if a file named `gradle/libs.versions.toml` exists, Gradle automatically registers a catalog called `libs` from it — no settings code needed. Build scripts then reference entries through generated type-safe accessors like `libs.guava`. You can also declare catalogs explicitly in `settings.gradle.kts` under `dependencyResolutionManagement { versionCatalogs { ... } }`, which lets you create additional named catalogs or build one programmatically. Catalogs are resolved at configuration time and are visible to all projects, which is what makes them a *sharing* mechanism rather than a per-project convenience.

code

kotlin · 13 lines
kotlin
// settings.gradle.kts — explicit form of what the convention does automatically
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("gradle/libs.versions.toml"))
        }
    }
}

// any build.gradle.kts
dependencies {
    implementation(libs.guava)
}

go deeper

for a junior

Know it's a shared dependency list and that gradle/libs.versions.toml auto-creates libs.

for a middle

Explain the settings-level dependencyResolutionManagement { versionCatalogs { create } } block and why it lives in settings.

for a senior

Distinguish the convention from explicit declaration, and reason about when each is appropriate across a multi-module build.

for a principal

Frame the catalog as the org-wide single source of truth and a governance point for dependency declarations.

## What a version catalog is A **version catalog** is a build-wide registry that maps short aliases to dependency coordinates and versions. Instead of repeating `"com.google.guava:guava:33.0.0-jre"` in every module, you declare it once and refer to it by alias everywhere. It is purely a *declaration/sharing* tool — it does not change resolution rules, conflict resolution, or which repositories are searched. A catalog holds four kinds of entries: **versions** (named version numbers), **libraries** (group + name + version), **bundles** (named groups of libraries), and **plugins** (plugin id + version). This question focuses on how a catalog comes to *exist* and be *shared*, not on the file format itself. ## The conventional `libs` catalog Gradle has one built-in convention: if a file exists at `gradle/libs.versions.toml` (relative to the root build), Gradle **automatically** registers a catalog named `libs`. You do not write any settings code for this. The name `libs` is just the default — the file's *base name* (`libs`) becomes the catalog name. Place `foo.versions.toml` in `gradle/` and you'd get a `foo` catalog too. From that catalog Gradle generates **type-safe accessors** available in every project's build script, e.g. `libs.guava`, `libs.versions.junit`, `libs.bundles.testing`. ## Declaring catalogs explicitly When you need more than the convention — extra catalogs, a programmatically built catalog, or importing a catalog published as an artifact — you declare them in `settings.gradle.kts`: ```kotlin dependencyResolutionManagement { versionCatalogs { create("libs") { from(files("gradle/libs.versions.toml")) } } } ``` `dependencyResolutionManagement` is a settings-level block; `versionCatalogs` is a container of catalogs you can `create(...)`. Inside, `from(...)` imports a file or a published catalog dependency, and `library(...)` / `version(...)` add entries programmatically. ## Why it lives in settings, not a build script Catalogs are a **build-wide** concept, so they are configured in `settings.gradle.kts` (which runs once for the whole build) rather than in any single `build.gradle.kts`. That placement is what makes the accessors visible to all projects simultaneously.

  • If you put a file at `gradle/libs.versions.toml`, do you still need the `create("libs") { from(...) }` block?
    No. Gradle auto-registers the `libs` catalog from that conventional path. The explicit block is only needed for non-default file locations, extra catalogs, or programmatic entries — and writing it for the default path is redundant.
  • Where must the catalog be declared and why?
    In `settings.gradle.kts` under `dependencyResolutionManagement`, because catalogs are build-wide and settings runs once for the whole build, making the accessors visible to every project.

Like a shared address book for dependencies: write each contact once, dial everyone by name instead of memorizing phone numbers in every script.

saying these in an interview costs you the question

  • Saying the catalog is configured per-module in build.gradle.kts.
  • Claiming the catalog must always be named `libs` — the name comes from the file base name or the `create(name)` argument.

context

open as a page

Inside `dependencyResolutionManagement { versionCatalogs { create(...) } }`, how do you build a catalog from a file versus programmatically, and what does `from()` accept?

level: middleimportance: should knowfreq 52%

basics

~10 s

Use from(files("...toml")) to import a TOML file, or from("group:artifact:version") to import a published catalog. Or skip from and add entries directly with version(...), library(...), bundle(...), plugin(...).

open as a page

How do you publish a version catalog so other builds can import it, and how does the consuming build pull it in?

level: seniorimportance: should knowfreq 41%

basics

~20 s

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

open as a page

A team has several independent repos and wants one source of truth for dependency versions. Compare a checked-in shared `libs.versions.toml` versus a published version catalog, and when you'd pick each.

level: seniorimportance: should knowfreq 35%

basics

~20 s

A copied/checked-in TOML is simple but drifts across repos. A published catalog (version-catalog plugin) is a versioned artifact imported with from("g:a:v"), giving one governed source and controlled upgrades — at the cost of publishing infrastructure.

open as a page

When and how would you declare multiple named version catalogs in one build, and what are the trade-offs?

level: middleimportance: nice to knowfreq 28%

basics

~10 s

Call create("name") once per catalog inside versionCatalogs; each produces its own accessor root (e.g. libs.*, testLibs.*). Use it to separate concerns, but it adds cognitive overhead, so most builds keep a single libs.

open as a page