What can a Settings plugin do with the pluginManagement block, and why is it the only place to do it?
answer
- pluginManagement = where plugins resolve
- repositories / resolutionStrategy / eachPlugin
- includeBuild to supply plugins
- resolved in initialization phase
- must be first block in settings
basics
~10 spluginManagement controls where plugins are resolved (repositories), version/ID resolution rules (resolutionStrategy), and can includeBuild a build that supplies plugins. It must be in settings because plugin resolution happens during initialization, before build scripts run.
solid answer
~40 s`pluginManagement {}` lives in `settings.gradle(.kts)` and a `Plugin<Settings>` can call `settings.pluginManagement { ... }` to configure it programmatically. It governs how the `plugins {}` DSL resolves plugins across the whole build: `repositories {}` (defaults to the Gradle Plugin Portal), `resolutionStrategy { eachPlugin { ... } }` to map a plugin id to a specific artifact/version, `plugins {}` to declare default versions, and `includeBuild(...)` to source plugins from an included build. It must live in settings because plugin resolution happens during the **initialization phase** — Gradle has to know where to fetch plugins before it can evaluate any `build.gradle`. A settings convention plugin is the canonical way to standardize this across many repositories.
code
kotlin · 13 linessettings.pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.example.legacy") {
useModule("com.example:legacy-plugin:2.0")
}
}
}
}go deeper
Know that pluginManagement.repositories controls where plugins are downloaded from and defaults to the Plugin Portal.
Explain resolutionStrategy/eachPlugin remapping and why pluginManagement must live in settings due to the initialization phase.
Discuss standardizing plugin resolution (internal Nexus, id remapping) across repos via a settings plugin, plus the bootstrapping order.
Treat it as a supply-chain control point: pin and route plugin resolution org-wide, mirror the Plugin Portal, and enforce it through a shared settings plugin.
## What pluginManagement controls `pluginManagement {}` is a Settings-level block that configures **plugin resolution** for the entire build tree. Inside it you can set: - **`repositories {}`** — where the `plugins { id("...") }` DSL looks for plugins. Defaults to `gradlePluginPortal()` if unspecified. - **`resolutionStrategy { eachPlugin { ... } }`** — intercept each plugin request and remap its id to a specific `useModule("group:artifact:version")` or `useVersion("...")`. Useful for mapping a marker id to a non-standard coordinate. - **`plugins {}`** — declare default versions so build scripts can apply `id("x")` without a version. - **`includeBuild("...")`** — include a build that *provides* a plugin, so the plugin can be developed alongside its consumers. - **`includeBuild` of the settings-plugin source itself** when bootstrapping. ## Why it must be in settings Gradle resolves plugins during **initialization**, before configuration. By the time a `build.gradle.kts` runs its `plugins {}` block, Gradle must already know the repositories and version rules. Those are fixed in the `Settings` model, which is why `pluginManagement` is a settings-only concept and why a `Plugin<Settings>` is the right place to set it programmatically. ## Doing it from a settings plugin ```kotlin class ConventionsSettingsPlugin : Plugin<Settings> { override fun apply(settings: Settings) { settings.pluginManagement { repositories { gradlePluginPortal() maven(url = "https://nexus.example.com/repository/plugins") } resolutionStrategy { eachPlugin { if (requested.id.namespace == "com.example") { useModule("com.example:gradle-plugins:${requested.version}") } } } } } } ``` ## Ordering gotcha In a hand-written `settings.gradle.kts`, `pluginManagement {}` must be the **first** block — even before `plugins {}`. When you encapsulate it in a settings plugin, the plugin itself must already be resolvable (e.g. via `buildSrc` or `pluginManagement { includeBuild(...) }` in the consuming settings file), which is the classic bootstrapping subtlety.
- How would you make a build resolve a marker plugin id to a custom artifact coordinate?Use pluginManagement.resolutionStrategy.eachPlugin and call useModule("group:artifact:version") when requested.id matches, mapping the id to the real coordinate.
- Why must pluginManagement be the first block in a hand-written settings file?The plugins {} block (and any subsequent resolution) needs the repositories already configured, so pluginManagement must be parsed first to set them up.
saying these in an interview costs you the question
- Confusing pluginManagement.repositories (where plugins come from) with dependencyResolutionManagement.repositories (where regular dependencies come from).
- Putting pluginManagement in build.gradle.