skip to content

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%

answer

  1. from(files()) vs from("g:a:v")
  2. from accepts exactly one source
  3. version / library / bundle / plugin builders
  4. versionRef ties library to version
  5. mix import + programmatic

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(...).

solid answer

~30 s

Inside `versionCatalogs { create("libs") { ... } }` you have two construction strategies. **Import** with `from(...)`: pass `files("gradle/libs.versions.toml")` to read a TOML file, or pass a single dependency notation like `from("com.acme:catalog:1.0")` (a published `version-catalog` artifact). `from` accepts **exactly one** file or one dependency — multiple `from` calls or multiple files are rejected. **Build programmatically**: skip `from` and call `version("junit", "5.10")`, `library("junit", "org.junit.jupiter", "junit-jupiter").versionRef("junit")`, `bundle("testing", listOf("junit"))`, and `plugin("spring", "org.springframework.boot").version("3.2.0")`. You can combine: `from` a base file and then add or override entries with these builder methods, which is handy for injecting computed versions or convention-plugin defaults.

code

kotlin · 11 lines
kotlin
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("gradle/libs.versions.toml"))
            // add a computed entry on top of the imported file
            val ci = providers.environmentVariable("CI_LIB_VERSION").orElse("1.0.0")
            version("internal", ci.get())
            library("internal-core", "com.acme", "core").versionRef("internal")
        }
    }
}

go deeper

for a junior

Recognize from(files(...)) imports the TOML and that entries also exist programmatically.

for a middle

Use the builder methods correctly and know from takes exactly one source.

for a senior

Choose between file import, published import, and programmatic construction per scenario and justify it.

for a principal

Standardize a programmatic settings-plugin approach to inject org-wide catalog defaults across many builds.

## The `create` block builder `versionCatalogs.create(name) { ... }` gives you a `VersionCatalogBuilder`. Everything inside configures one catalog. There are two ways to populate it, and they can be mixed. ## Importing with `from(...)` `from` seeds the catalog from an external source and accepts **one** argument: - A **file collection** with a single TOML file: `from(files("gradle/libs.versions.toml"))`. This is the explicit equivalent of the default convention. - A **dependency notation** for a *published catalog*: `from("com.acme:platform-catalog:2.1")`. The resolved artifact is a `version-catalog`-typed module produced by the `version-catalog` plugin (covered separately). Constraints: you may call `from` **only once**, and a file collection passed to it must contain **exactly one** file — Gradle fails the build otherwise. This is deliberate: a catalog has a single authoritative source. ## Building programmatically Without `from`, you declare entries directly: ```kotlin dependencyResolutionManagement { versionCatalogs { create("libs") { version("junit", "5.10.2") library("junit-api", "org.junit.jupiter", "junit-jupiter-api").versionRef("junit") library("guava", "com.google.guava:guava:33.0.0-jre") bundle("junit", listOf("junit-api")) plugin("ktlint", "org.jlleitschuh.gradle.ktlint").version("12.1.0") } } } ``` - `version(alias, value)` defines a reusable version; `versionRef(alias)` points a library at it. - `library(alias, group, name)` returns a builder you finish with `.version(...)` or `.versionRef(...)`; the two-arg `library(alias, "g:n:v")` form takes full notation. - `bundle(alias, listOf(...))` groups library aliases. - `plugin(alias, id).version(...)` defines plugin entries used in `plugins { alias(libs.plugins.x) }`. ## Mixing import and builder calls A powerful pattern: `from(files(...))` a base catalog, then add a few programmatic entries (e.g. a version derived from `providers.environmentVariable(...)` or a setting), or define extras a convention plugin needs. The builder methods layer on top of the imported entries. ## Why programmatic at all Programmatic construction matters when versions are computed, injected by a settings/convention plugin, or assembled for many builds from a shared script — anywhere a static file can't express the logic.

  • Can you call `from()` twice to merge two TOML files into one catalog?
    No. `from` may be invoked only once and its file collection must contain exactly one file; Gradle fails otherwise. Merge by importing one and adding the rest with `library`/`version` builder calls, or by creating separate named catalogs.
  • What's the difference between `from(files(...))` and `from("g:a:v")`?
    `files(...)` reads a local TOML file; the dependency-notation form resolves a *published* version-catalog artifact from a repository, produced elsewhere by the `version-catalog` plugin.

saying these in an interview costs you the question

  • Saying you can pass multiple files to `from` — it rejects more than one.
  • Confusing `version(...)` (defines a version) with `versionRef(...)` (references one).

context