Inside `dependencyResolutionManagement { versionCatalogs { create(...) } }`, how do you build a catalog from a file versus programmatically, and what does `from()` accept?
answer
- from(files()) vs from("g:a:v")
- from accepts exactly one source
- version / library / bundle / plugin builders
- versionRef ties library to version
- mix import + programmatic
basics
~10 sUse 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 sInside `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 linesdependencyResolutionManagement {
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
Recognize from(files(...)) imports the TOML and that entries also exist programmatically.
Use the builder methods correctly and know from takes exactly one source.
Choose between file import, published import, and programmatic construction per scenario and justify it.
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).