skip to content

Version Catalog TOML

The gradle/libs.versions.toml file and its versions, libraries, bundles, and plugins tables. Asked because catalogs are now the standard way to keep version strings out of build scripts entirely.

on this pageshow

questions

6

What is the gradle/libs.versions.toml file, and what are the four tables it can contain?

level: juniorimportance: must knowfreq 70%

answer

  1. gradle/libs.versions.toml = catalog named libs
  2. four tables: versions, libraries, bundles, plugins
  3. module vs group+name
  4. version.ref points into [versions]
  5. TOML, auto-generated accessors

basics

~10 s

It's Gradle's version catalog: a TOML file at gradle/libs.versions.toml listing dependency coordinates and versions in one place. Its four tables are [versions], [libraries], [bundles], and [plugins].

solid answer

~40 s

`gradle/libs.versions.toml` is a Gradle **version catalog**: a central, declarative file where you list dependency versions and coordinates once and reference them everywhere. Gradle auto-creates a catalog named `libs` from this conventional path and generates type-safe accessors. It has four tables: - **[versions]** — named version strings (e.g. `junit = "5.10.0"`). - **[libraries]** — dependency declarations by `module`/`group`+`name`, with a literal `version` or a `version.ref` pointing into `[versions]`. - **[bundles]** — named lists of library aliases applied together. - **[plugins]** — plugin `id` + version, for use in `plugins {}` blocks. The file is TOML, so it's tooling-friendly and decoupled from build logic.

code

toml · 11 lines
toml
[versions]
junit = "5.10.0"

[libraries]
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }

[bundles]
testing = ["junit-jupiter"]

[plugins]
spring-boot = { id = "org.springframework.boot", version = "3.2.3" }

go deeper

for a junior

Name the path and the four tables; show one library entry. Basic recall is enough.

for a middle

Explain version.ref vs inline version, module vs group+name, and that accessors are auto-generated from aliases.

for a senior

Discuss why centralization matters for multi-module repos and how the libs convention removes boilerplate registration.

for a principal

Frame catalogs as governance: a single curated dependency surface that can be shared and enforced org-wide.

## What a version catalog is A **version catalog** is Gradle's built-in mechanism for centralizing dependency coordinates and versions. Before catalogs, versions were scattered across `build.gradle` files or hidden in `ext` properties; the catalog gives you a single, declarative, TOML-formatted source of truth that every module shares. Gradle recognizes one **conventional** catalog automatically: any file at `gradle/libs.versions.toml` becomes a catalog named `libs`, with no extra configuration. From it Gradle generates **type-safe accessors** you use in build scripts (e.g. `libs.junit.jupiter`). ## The four tables TOML organizes data into `[tables]`. A catalog file may contain four: - **`[versions]`** — maps a name to a version string. These are reusable so multiple libraries can share one version. Example: `junit = "5.10.0"`. - **`[libraries]`** — declares dependencies. Each entry needs coordinates, supplied either as `module = "group:name"` or as separate `group`/`name` keys, plus a version given inline (`version = "..."`) or by reference (`version.ref = "junit"`). - **`[bundles]`** — a named list of library aliases that are commonly used together, so you can add them with one accessor. - **`[plugins]`** — declares Gradle plugins with an `id` and a version (or `version.ref`), consumed in the `plugins {}` block via accessors. ## Naming and accessors Aliases use letters, digits, `-`, `_`, and `.` as separators; Gradle maps `-`/`_`/`.` to nested accessors. So a library alias `commons-lang3` becomes `libs.commons.lang3`. This is why catalog aliases read as dotted paths in scripts. ## Example ```toml [versions] junit = "5.10.0" spring = "6.1.4" [libraries] junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } spring-core = { group = "org.springframework", name = "spring-core", version.ref = "spring" } [bundles] testing = ["junit-jupiter"] [plugins] spring-boot = { id = "org.springframework.boot", version = "3.2.3" } ``` In a build script you'd then write `implementation(libs.spring.core)`, `testImplementation(libs.bundles.testing)`, and `alias(libs.plugins.spring.boot)`.

  • Why does the file have to live at gradle/libs.versions.toml specifically?
    That exact path is the convention Gradle uses to auto-create a catalog named `libs` without any settings configuration. Other paths/names require explicit registration in settings.gradle.
  • What's the difference between a [versions] entry and a [libraries] entry?
    A [versions] entry is just a named version string with no coordinates. A [libraries] entry is a full dependency (group+name) that may reference a [versions] entry via version.ref.

saying these in an interview costs you the question

  • Thinking the catalog is a plugin you must apply — it's built into Gradle.
  • Saying the file format is YAML or properties — it is TOML.
  • Claiming [versions] entries are dependencies themselves rather than reusable version strings.

context

open as a page

In a [libraries] entry, when would you use version.ref versus an inline version, and how does module differ from group+name?

level: middleimportance: must knowfreq 60%

basics

~10 s

Use version.ref to point a library at a shared name in [versions] so many libraries upgrade together; use inline version for a one-off. module = "group:name" is shorthand for separate group and name keys.

open as a page

What is the [bundles] table for, and how do bundle entries relate to [libraries] aliases?

level: middleimportance: should knowfreq 45%

basics

~10 s

A [bundles] entry is a named list of [libraries] aliases that are commonly used together, so you can add them all with one accessor instead of declaring each dependency separately.

open as a page

How does the [plugins] table work in libs.versions.toml, and how is it consumed differently from [libraries]?

level: middleimportance: should knowfreq 50%

basics

~10 s

[plugins] entries declare a plugin id and version (e.g. id = "...", version = "..."). You consume them in the plugins {} block via alias(libs.plugins.<name>), not in dependencies {}.

open as a page

What naming rules govern catalog aliases in the TOML, and what common errors do invalid names cause?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Aliases use letters, digits and the separators -, _, . which all map to dotted accessors. Names must start with a letter, can't be reserved words like extensions/class/convention, and the leading segment can't collide with another alias's prefix.

open as a page

How are rich version constraints expressed inside a libs.versions.toml entry, and what do require, strictly, prefer, and reject mean there?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Instead of a plain version string, an entry's version can be an object: version = { require = "..." }, strictly, prefer, or reject. require/strictly set the chosen version (strictly is a hard fail), prefer is a tie-breaker, reject excludes versions.

open as a page