When and how would you declare multiple named version catalogs in one build, and what are the trade-offs?
answer
- container → many create(name)
- name = accessor root prefix
- no merging across catalogs
- split on ownership/source boundary
- default to one libs
basics
~10 sCall 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.
solid answer
~50 s`versionCatalogs` is a container, so you can `create` several catalogs in the same settings file, each with a distinct name that becomes its accessor prefix. For example one `libs` for production dependencies and a `testLibs` from a different TOML or a published catalog. Reasons to split: separating internal/shared catalogs from local ones, importing a published org catalog alongside a project-local one, or isolating a large plugin set. The cost is real: contributors must remember which prefix holds what, IDE auto-complete is spread across roots, and overlap between catalogs invites confusion. Gradle does not merge catalogs, so a dependency declared in two catalogs exists twice under different prefixes. The common guidance is to default to a single `libs` and introduce extra catalogs only when there's a concrete sharing or ownership boundary — e.g. a corporate catalog imported by `from("g:a:v")` plus a project `libs` for local-only additions.
code
kotlin · 11 linesdependencyResolutionManagement {
versionCatalogs {
create("libs") { from(files("gradle/libs.versions.toml")) }
create("corpLibs") { from("com.acme:corp-catalog:3.4") }
}
}
// build.gradle.kts
dependencies {
implementation(libs.guava)
implementation(corpLibs.logging)
}go deeper
Know more than one catalog is possible and the name becomes the prefix.
Declare several catalogs and articulate when the split is justified versus noise.
Weigh discoverability and no-merge semantics; recommend single-catalog defaults with deliberate exceptions.
Set an org convention for catalog topology — e.g. one published corp catalog plus a thin local catalog per repo.
## Multiple catalogs are allowed `dependencyResolutionManagement { versionCatalogs { ... } }` exposes a *container*. Each `create(name) { ... }` registers an independent catalog, and the **name is the accessor root** in build scripts: ```kotlin dependencyResolutionManagement { versionCatalogs { create("libs") { from(files("gradle/libs.versions.toml")) } create("corpLibs") { from("com.acme:corp-catalog:3.4") } create("testLibs") { from(files("gradle/test.versions.toml")) } } } ``` Now build scripts use `libs.guava`, `corpLibs.logging`, `testLibs.junit` — three separate namespaces. ## When it earns its keep - **Ownership boundary**: a centrally-published `corpLibs` (governed by a platform team) sits beside a project-local `libs` that teams edit freely. - **Source boundary**: one catalog comes from a file, another from a published artifact — they can't be a single `from`, so separate catalogs is the natural split. - **Scope isolation**: keeping a sprawling set of plugin/test entries out of the main namespace. ## The costs - **Discovery**: developers must know which prefix holds a given library; this is the biggest tax in practice. - **No merging**: Gradle never combines catalogs. The same coordinate declared in two catalogs is two separate aliases; there is no de-duplication or override across catalogs. - **Tooling**: accessors are generated per catalog, so auto-complete and refactors are scoped to each root. ## Guidance Default to a single `libs`. Reach for additional catalogs only when a real boundary (ownership, source, or scope) exists — most commonly a published corporate catalog imported via `from("g:a:v")` alongside a small project-local `libs`. Avoid splitting purely by category (ui/db/test) inside one repo; bundles and a single namespace usually serve better and keep the cognitive model simple.
- If two catalogs declare the same library coordinate, what happens?Nothing special — Gradle does not merge catalogs. You simply have two aliases under different prefixes pointing at the same coordinate; there is no conflict, override, or de-duplication between catalogs.
- What's a clean reason to use two catalogs rather than one?Different sources/ownership: a published, centrally-governed catalog imported with `from("g:a:v")` alongside a project-local `libs` from a TOML file — since one `from` can't combine a published artifact and a local file.
saying these in an interview costs you the question
- Assuming Gradle merges or overrides entries across multiple catalogs.
- Splitting catalogs by feature category (ui/db) inside one repo — usually adds overhead without a real boundary.