What does the resolutionStrategy { eachPlugin { ... } } block inside pluginManagement do, and when would you use it?
answer
- settings.gradle pluginManagement
- runs once per requested plugin
- useVersion vs useModule
- plugin marker artifact redirect
- requested.id / requested.version
basics
~10 sIt is a hook in settings.gradle that runs for every plugin request, letting you override the resolved version or remap a plugin id to a module (artifact coordinates) centrally.
solid answer
~40 s`pluginManagement { resolutionStrategy { eachPlugin { ... } } }` lives in `settings.gradle(.kts)` and runs a callback for **each** plugin requested via the `plugins {}` block. Inside, `target.requested` exposes the plugin id and version, and you can call `useVersion("x.y.z")` to pin/override the version, or `useModule("group:artifact:version")` to tell Gradle which artifact actually provides that plugin id. The classic use case is consuming a plugin published only as a normal Maven artifact (no Plugin Marker), or centrally pinning a version coming from a version variable so individual build scripts can apply `id 'foo'` without a version. It runs before Gradle resolves the plugin marker artifact, so it intercepts resolution itself rather than just dependency versions.
code
groovy · 13 lines// settings.gradle
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == 'com.example.foo') {
useVersion('1.4.0') // pin/override version
}
if (requested.id.id == 'org.legacy.tool') {
useModule("org.legacy:tool-gradle-plugin:${requested.version}")
}
}
}
}go deeper
Know it exists in settings.gradle and can override a plugin version centrally.
Explain useVersion vs useModule and the plugin-marker concept; give the central-pinning use case.
Compare to version catalogs, explain when each is preferable, and discuss id-to-module remapping for non-marker plugins.
Frame it within an org-wide plugin governance strategy (convention plugins, catalogs, marker publishing) and the trade-offs of imperative hooks vs declarative catalogs.
## What problem it solves When you write `plugins { id 'com.example.foo' version '1.2.3' }`, Gradle resolves a **plugin marker artifact** at coordinates `com.example.foo:com.example.foo.gradle.plugin:1.2.3`. That marker is a tiny POM that redirects to the real implementation jar. Some plugins are published *only* as ordinary library artifacts and never publish a marker, and sometimes you want to override a plugin's version from one central place rather than editing every build script. The `eachPlugin` hook is where you intercept this. ## Where it lives It must be in **`settings.gradle(.kts)`**, inside `pluginManagement`, because plugin resolution happens at settings evaluation time — before any project build script runs. ``` pluginManagement { resolutionStrategy { eachPlugin { // runs once per requested plugin } } } ``` ## The PluginResolveDetails API The closure receives a `PluginResolveDetails` (referenced as `this`/`it`): - `requested` — a `PluginRequest` with `requested.id` (e.g. `com.example.foo`) and `requested.version`. - `useVersion(String)` — override/set the version Gradle resolves for this plugin. - `useModule("group:artifact:version")` — bypass the plugin-marker lookup entirely and resolve the implementation from these explicit coordinates. - `useTarget(...)` — lower-level form taking a notation. ## Typical patterns 1. **Central version pinning** — strip versions out of build scripts, set them once: ``` eachPlugin { if (requested.id.id == "com.example.foo") { useVersion("1.4.0") } } ``` 2. **Map an id to a non-marker artifact** — for plugins without a published marker: ``` eachPlugin { if (requested.id.id == "org.legacy.tool") { useModule("org.legacy:tool-gradle-plugin:${requested.version}") } } ``` ## Where it sits in the bigger picture This is one of several mechanisms (alongside `plugins {}` with versions, a version catalog's `[plugins]` table, and `buildscript {}` classpath dependencies). The version catalog has become the more modern, declarative way to centralize plugin versions, but `eachPlugin` remains essential for **id-to-module remapping** and dynamic/conditional logic that a catalog cannot express.
- Why must this go in settings.gradle and not a build.gradle?Plugin resolution for the `plugins {}` block happens during settings evaluation, before project build scripts are configured, so the hook must be registered in pluginManagement in settings.
- What is the difference between useVersion and useModule?useVersion only changes the version while keeping Gradle's plugin-marker lookup; useModule replaces the whole coordinate (group:artifact:version), bypassing the marker — used when no marker is published.
saying these in an interview costs you the question
- Claiming eachPlugin can go in a project build.gradle file.
- Confusing it with dependency resolutionStrategy (configurations) — that governs library deps, not plugins.
- Saying it runs once total rather than once per requested plugin.