How would you centrally pin or override a plugin version for all build scripts using resolutionStrategy?
answer
- version once in settings
- build scripts omit version
- match requested.id.id then useVersion
- compare to catalog [plugins]
- guard with id check
basics
~10 sIn settings.gradle's pluginManagement, use resolutionStrategy.eachPlugin and call useVersion(...) when requested.id matches, so build scripts apply the plugin id without specifying a version.
solid answer
~40 sI declare the version once in `settings.gradle` and let build scripts request the plugin by id only. Inside `pluginManagement { resolutionStrategy { eachPlugin { ... } } }`, I match on `requested.id.id` and call `useVersion("x.y.z")`. Build scripts then write `plugins { id 'com.example.foo' }` with no version, and the hook supplies it. This centralizes upgrades — one edit in settings updates every module — and prevents version drift across a multi-module build. It also lets me override a version that a third-party convention plugin would otherwise pull in. In modern Gradle I'd usually reach for a **version catalog** `[plugins]` table first for static pinning, and keep `eachPlugin` for conditional/dynamic logic (e.g. environment-based versions) the catalog cannot express.
code
kotlin · 13 lines// settings.gradle.kts
pluginManagement {
val fooVersion = "1.4.0"
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.example.foo") {
useVersion(fooVersion)
}
}
}
}
// build.gradle.kts of any module:
plugins { id("com.example.foo") } // no version neededgo deeper
Know that you can move the version into settings and apply by id only.
Show the eachPlugin + useVersion pattern with an id guard and explain the multi-module benefit.
Contrast with version catalogs and justify when the imperative hook is still warranted.
Define an org policy: catalogs for static, convention plugins to encapsulate, eachPlugin as an escape hatch; consider caching and reproducibility impacts.
## The goal: one source of truth for plugin versions In a multi-module build, repeating `version '1.2.3'` next to every `id 'com.example.foo'` invites drift and makes upgrades painful. `eachPlugin` lets the **version live once** in settings. ## Mechanics The `plugins {}` block in a build script can request a plugin **without** a version. When Gradle resolves it, the `eachPlugin` callback fires; if you call `useVersion`, that becomes the resolved version. ``` pluginManagement { resolutionStrategy { eachPlugin { switch (requested.id.id) { case 'com.example.foo': useVersion('1.4.0'); break case 'com.example.bar': useVersion('2.1.0'); break } } } } ``` A common refinement is sourcing the version from a `gradle.properties` value or an extra property so even the settings file is data-driven. ## Reading the requested version `requested.version` is the version the build script asked for (may be null if omitted). You can override unconditionally, or only when null, or only to *raise* a floor — `eachPlugin` gives you full imperative control. ## Versus the version catalog Gradle 7+ version catalogs expose a `[plugins]` table: ``` [plugins] foo = { id = "com.example.foo", version = "1.4.0" } ``` and scripts use `alias(libs.plugins.foo)`. This is declarative, type-safe in Kotlin DSL, and the **preferred** modern approach for static pinning. Choose `eachPlugin` when you need logic — conditional versions, id-to-module remapping, or programmatic computation. ## Pitfalls - The hook runs for **every** plugin, including ones you don't intend to touch — always guard with an id check. - `useVersion` still needs a published plugin marker; if there is none, use `useModule`. - Settings-level changes invalidate plugin resolution caching, so keep the logic cheap.
- When would you prefer a version catalog over eachPlugin for pinning?For static version pinning catalogs are declarative, type-safe, and shareable across builds; prefer eachPlugin only when you need conditional or computed version logic, or id-to-module remapping.
- What happens if you call useVersion but never guard with an id check?The callback fires for every requested plugin, so you'd attempt to set that version on all of them — almost always a bug; always match requested.id.id first.
saying these in an interview costs you the question
- Forgetting that the callback runs for every plugin, not just the one you care about.
- Claiming useVersion works without a published plugin marker (it needs one; otherwise use useModule).
- Saying you can pin in build.gradle's plugins block centrally — pinning per script is exactly what this avoids.