skip to content

What does the resolutionStrategy { eachPlugin { ... } } block inside pluginManagement do, and when would you use it?

level: middleimportance: must knowfreq 45%

answer

  1. settings.gradle pluginManagement
  2. runs once per requested plugin
  3. useVersion vs useModule
  4. plugin marker artifact redirect
  5. requested.id / requested.version

basics

~10 s

It 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
groovy
// 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

for a junior

Know it exists in settings.gradle and can override a plugin version centrally.

for a middle

Explain useVersion vs useModule and the plugin-marker concept; give the central-pinning use case.

for a senior

Compare to version catalogs, explain when each is preferable, and discuss id-to-module remapping for non-marker plugins.

for a principal

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.

context