skip to content

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%

answer

  1. version.ref = shared version, one edit upgrades family
  2. inline version = one-off literal
  3. module = group:name shorthand
  4. group + name = expanded, identical
  5. version.{require,strictly,prefer} objects

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.

solid answer

~40 s

A `[libraries]` entry must name coordinates and a version. Coordinates come either as **`module = "group:name"`** (one colon-separated string) or as separate **`group`** and **`name`** keys — they're equivalent; `module` is just more compact. For the version you choose between: - **`version.ref = "junit"`** — points into the `[versions]` table. Use this when several libraries should share one version (e.g. all JUnit 5 artifacts), so a single edit in `[versions]` bumps them all together. - **inline `version = "3.12.0"`** — a literal pinned to that one library. Use it for a one-off whose version nothing else tracks. `version.ref` is the workhorse for related artifact families and BOM-style alignment; inline versions keep simple, isolated dependencies terse.

code

toml · 7 lines
toml
[versions]
junit = "5.10.2"

[libraries]
junit-api    = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
guava        = { module = "com.google.guava:guava", version = { strictly = "33.0.0-jre" } }

go deeper

for a junior

Show one library entry with an inline version; know module = group:name.

for a middle

Explain when to share a version.ref vs inline, and the equivalence of module and group+name.

for a senior

Bring in rich version objects (require/strictly/prefer) and how version.ref keeps artifact families aligned.

for a principal

Discuss catalog-level version governance: refs as the single control point and strictly for locking critical deps org-wide.

## Anatomy of a [libraries] entry Every library alias maps to a small TOML inline table with two responsibilities: **coordinates** (which artifact) and **version** (which release). ### Coordinates: module vs group + name Gradle dependency coordinates are `group:name:version`. In the catalog you give just the `group:name` part two ways: ```toml # compact form commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.14.0" } # expanded form (identical result) commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = "3.14.0" } ``` They produce the same dependency. `module` is preferred for brevity; the split `group`/`name` form is handy when generating the file programmatically. ### Version: ref vs inline The version slot accepts: - **`version.ref`** — a key into `[versions]`. This creates a single point of control. Artifact families that must move in lockstep (e.g. `junit-jupiter-api`, `junit-jupiter-engine`, `junit-jupiter-params`) all reference one `junit` version; bumping `[versions].junit` upgrades every consumer at once. - **inline `version`** — a literal string. Good for a standalone library no other entry tracks. - **rich constraints** — instead of a plain string the version can be an object: `version = { require = "1.5" }`, `version = { strictly = "1.5" }`, or `version = { prefer = "1.5" }`. `require` states a minimum-acceptable preferred version (still upgradable by conflict resolution), while `strictly` forbids the resolver from selecting anything outside the range — it fails the build instead. These are how the TOML expresses version constraints declaratively. ### Why version.ref matters in practice Sharing a `version.ref` is the catalog's main lever for **keeping related modules aligned without a BOM**. It also makes Renovate/Dependabot-style updates land in one place. Overusing inline versions scatters the same number across many entries and reintroduces the drift catalogs exist to prevent. ## Worked example ```toml [versions] junit = "5.10.2" [libraries] junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } guava = { module = "com.google.guava:guava", version = { strictly = "33.0.0-jre" } } ``` Here both JUnit artifacts move together via one `[versions]` edit, while Guava is pinned strictly and independently.

  • Can a [libraries] entry omit the version entirely?
    Yes — `{ module = "..." }` with no version is legal. It declares the dependency without a version, expecting the actual version to come from a platform/BOM or another constraint.
  • What's the difference between version.require and version.strictly in the TOML?
    `require` is a preferred minimum that conflict resolution may still upgrade; `strictly` is a hard constraint — if resolution would pick something outside it, the build fails rather than silently upgrading.

saying these in an interview costs you the question

  • Claiming module and group+name behave differently — they're equivalent.
  • Saying version.ref points at a [libraries] alias — it points into [versions].
  • Treating strictly and require as interchangeable.

context