skip to content

What can a Settings plugin do with the pluginManagement block, and why is it the only place to do it?

level: middleimportance: must knowfreq 50%

answer

  1. pluginManagement = where plugins resolve
  2. repositories / resolutionStrategy / eachPlugin
  3. includeBuild to supply plugins
  4. resolved in initialization phase
  5. must be first block in settings

basics

~10 s

pluginManagement 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 lines
kotlin
settings.pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id == "com.example.legacy") {
                useModule("com.example:legacy-plugin:2.0")
            }
        }
    }
}

go deeper

for a junior

Know that pluginManagement.repositories controls where plugins are downloaded from and defaults to the Plugin Portal.

for a middle

Explain resolutionStrategy/eachPlugin remapping and why pluginManagement must live in settings due to the initialization phase.

for a senior

Discuss standardizing plugin resolution (internal Nexus, id remapping) across repos via a settings plugin, plus the bootstrapping order.

for a principal

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.

context