Show how the `apply false` pattern looks when versions come from a Gradle version catalog (`libs.versions.toml`), and explain what stays the same versus what changes compared to inline versions.
answer
- [plugins] block in libs.versions.toml
- alias(libs.plugins.x) apply false at root
- alias(libs.plugins.x) in subprojects
- dash becomes dotted accessor
- same mechanic, version relocated
basics
~10 sThe version moves into [plugins] in libs.versions.toml. The root writes alias(libs.plugins.kotlin.jvm) apply false; subprojects write alias(libs.plugins.kotlin.jvm). The apply false resolve-but-don't-activate mechanic is unchanged.
solid answer
~40 sWith a version catalog, plugin versions live in `gradle/libs.versions.toml` under `[plugins]` (each entry has an `id` and `version.ref`). In the **root** build you still pin once, but via an alias: `alias(libs.plugins.kotlin.jvm) apply false`. Each **subproject** applies with `alias(libs.plugins.kotlin.jvm)` — no version, just like the inline case. What *stays the same*: the single-versioned-request-at-root rule, `apply false` meaning resolve-without-apply, subprojects applying without a version. What *changes*: the version string is no longer in any build script — it's centralized in the TOML, type-safe accessors (`libs.plugins.…`) replace string ids, and Dependabot/Renovate can bump versions in one well-known file. It's the same architecture with the version source relocated.
code
toml · 11 lines# gradle/libs.versions.toml
[versions]
kotlin = "1.9.24"
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
# root build.gradle.kts:
# plugins { alias(libs.plugins.kotlin.jvm) apply false }
# app/build.gradle.kts:
# plugins { alias(libs.plugins.kotlin.jvm) }go deeper
Recognize that catalog plugin aliases exist and versions live in the TOML.
Write the full root alias(...) apply false + subproject alias(...) layout and map TOML keys to accessors.
Explain the same-architecture/relocated-version point and the type-safety and automated-bump benefits.
Discuss shared/published catalogs across repos and governance of plugin versions org-wide.
## The catalog declaration A version catalog is a `gradle/libs.versions.toml` file Gradle reads to generate type-safe `libs.*` accessors. Plugins go under `[plugins]`: ```toml [versions] kotlin = "1.9.24" [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } shadow = { id = "com.gradleup.shadow", version = "8.3.0" } ``` ## Root: pin once with apply false ```kotlin // root build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.shadow) apply false } ``` `alias(libs.plugins.kotlin.jvm)` expands to the id + version from the catalog. Adding `apply false` does exactly what it did with inline versions: resolve and pin, don't apply to the root. The single-versioned-request rule still holds — the alias *is* a versioned request, so it must appear once. ## Subprojects: apply by alias, no version ```kotlin // app/build.gradle.kts plugins { alias(libs.plugins.kotlin.jvm) // no version; inherited } ``` Note `kotlin-jvm` in TOML becomes `libs.plugins.kotlin.jvm` (dash → dotted accessor). ## Same vs. different | Aspect | Inline version | Version catalog | |---|---|---| | Where version lives | in a build script | `libs.versions.toml` | | Root declaration | `id("…") version "…" apply false` | `alias(libs.plugins.x) apply false` | | Subproject | `id("…")` | `alias(libs.plugins.x)` | | `apply false` semantics | resolve, don't apply | identical | | One-versioned-request rule | applies | applies | ## Why teams prefer the catalog - Single, discoverable file for all versions (libs + plugins). - Type-safe accessors catch typos at configuration time. - Easy automated bumps and shared catalogs across repos. The key interview point: the catalog doesn't replace `apply false` — it feeds it. You still pin once at the root with `apply false` and apply by alias in subprojects.
- Does using a catalog remove the need for `apply false` at the root?No. The catalog only relocates the version string. You still declare the plugin once at the root — now as `alias(libs.plugins.x) apply false` — and apply by alias in subprojects. The resolve-but-don't-apply role of `apply false` is unchanged.
- Why does `kotlin-jvm` in TOML become `libs.plugins.kotlin.jvm` in the script?Gradle maps catalog keys to type-safe accessors, converting kebab-case segments separated by `-` into dotted accessor paths, so `kotlin-jvm` is reachable as `libs.plugins.kotlin.jvm`.
saying these in an interview costs you the question
- Saying the version catalog makes `apply false` unnecessary.
- Putting `version` on the subproject alias — it must be version-less, the alias carries the pinned version once at the root.