What is <pluginManagement> and why pin plugin versions there instead of declaring them in <plugins>?
answer
- like dependencyManagement, for plugins
- declares version + config, does NOT activate
- child lists groupId/artifactId, no version
- reproducible builds
- enforcer requirePluginVersions
basics
~20 s<pluginManagement> declares plugin versions and default config in a parent POM without actually enabling the plugin. Child modules that list the plugin (by groupId/artifactId, no version) inherit the pinned version and config, giving consistent, reproducible builds.
solid answer
~40 s`<pluginManagement>` (inside `<build>`) is the plugin analogue of `<dependencyManagement>`: it centralizes plugin **versions** and **default configuration** in a parent/aggregator POM but does **not** add the plugin to the build by itself. A module activates the plugin by listing it in `<build><plugins>` with just `groupId`/`artifactId` (no version); it then inherits the managed version and config and may override per module. Pinning versions there prevents Maven from silently resolving a plugin version (which can change between Maven releases or registry state), eliminating non-reproducible builds and the dreaded "works on my machine." It also lets you configure a plugin once for the whole reactor. The `maven-enforcer-plugin` `requirePluginVersions` rule can fail the build if any plugin lacks an explicit version, enforcing this discipline.
code
xml · 12 lines<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration><release>17</release></configuration>
</plugin>
</plugins>
</pluginManagement>
</build>go deeper
Knows it pins plugin versions in a parent POM.
Knows it does not activate the plugin and that children must still declare it.
Explains reproducibility motivation, config inheritance/merge, and enforcing pinned versions via enforcer.
Designs the parent/BOM-style POM hierarchy and governs plugin versioning across many modules/teams.
## The problem it solves If you use a plugin without specifying a `<version>`, Maven must *resolve* one. Historically it picked the latest available, and even now the resolved version can differ across Maven distributions or environments. That makes builds **non-reproducible** — the same source can compile or package differently on two machines or two days apart. ## <pluginManagement> vs <plugins> They live in different sub-elements of `<build>`: - **`<plugins>`** — actually adds/activates a plugin in *this* module's build. - **`<pluginManagement>`** — *declares* version and default config for a plugin, but does **not** activate it. It only takes effect when a module (this one or a descendant) also lists the plugin in `<plugins>`. ```xml <!-- parent / aggregator POM --> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.5</version> <configuration> <argLine>-Xmx512m</argLine> </configuration> </plugin> </plugins> </pluginManagement> </build> ``` ```xml <!-- child module POM: activates with inherited version + config --> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> </plugin> </plugins> </build> ``` ## Why this is the standard pattern - **Reproducibility** — every module uses the exact same plugin version. - **Single source of truth** — upgrade the version once in the parent. - **Consistent defaults** — shared `<configuration>` and even `<executions>` defined under management are inherited where the plugin is used. - **Cleaner child POMs** — modules list only `groupId`/`artifactId`. ## Enforcing it Add the `maven-enforcer-plugin` with the `requirePluginVersions` rule so the build fails if any plugin (including lifecycle-default ones) lacks an explicit version. This guarantees the discipline holds across the whole reactor. ## Subtlety: management config still merges Configuration declared in `<pluginManagement>` is merged with the activating `<plugins>` declaration using the normal Maven merge rules (with `combine.children`/`combine.self` available to control list merging) — so a module can add to or override the inherited defaults.
- Does putting a plugin in <pluginManagement> make it run?No. pluginManagement only supplies version and default config. The plugin must also be declared in <build><plugins> (in this module or a descendant) to actually participate in the build.
- How can you fail the build when a plugin version is unpinned?Use maven-enforcer-plugin with the requirePluginVersions rule; it errors if any plugin, including lifecycle defaults, has no explicit version.
- How does <pluginManagement> relate to <dependencyManagement>?Same idea on the plugin side: both centralize versions/config in a parent without activating anything, and both are activated by a matching, version-less declaration in the child.
saying these in an interview costs you the question
- Saying pluginManagement activates/runs the plugin
- Thinking it is only for versions and never config
- Letting plugins run with unpinned versions ('latest')
- Confusing it with <dependencyManagement> as if they were the same element