skip to content

How are <properties> and plugin configuration merged across the inheritance chain, and how does a child override them?

level: middleimportance: should knowfreq 45%

answer

  1. nearest wins
  2. Super POM -> parent -> child
  3. properties replace by key
  4. combine.self=override replaces
  5. combine.children append/merge

basics

~10 s

Properties and config are merged from the Super POM down through parents to the child. Anything the child redefines wins. So the child's value overrides the parent's, which overrides the Super POM's.

solid answer

~40 s

Maven builds the effective POM by merging from the top of the chain (Super POM) downward through each parent and finally the child; the **nearest definition wins**, so a child value overrides the parent's. Scalar elements like `<properties>` entries are simply replaced by the child. Plugin configuration merges per-plugin: by default child and parent configuration are *combined* element-by-element, but you control this with `combine.children` and `combine.self` attributes on configuration elements (e.g. `combine.self=override` to replace a list rather than append). For dependencies and plugins, identity is the coordinate (`groupId:artifactId`), so the child's matching entry overrides the parent's. Use `mvn help:effective-pom` to confirm the merged result.

code

xml · 14 lines
xml
<properties>
  <java.version>17</java.version>
  <skipTests>false</skipTests>
</properties>

<!-- in child, override one property and replace a plugin list -->
<properties>
  <java.version>21</java.version>
</properties>
<configuration>
  <arguments combine.self="override">
    <argument>--only-this</argument>
  </arguments>
</configuration>

go deeper

for a junior

Know the child's value overrides the parent's for properties.

for a middle

Explain the merge chain and that plugin config merges, not replaces, by default.

for a senior

Use combine.self/combine.children deliberately and verify with effective-pom.

for a principal

Define org conventions for what config lives in parent vs module to keep merges predictable.

## The merge model: nearest wins Maven assembles the **effective POM** by layering: Super POM -> grandparent -> parent -> child. The closest definition to the child takes precedence — same idea as method overriding. ## Properties `<properties>` are key/value pairs. A child key with the same name simply replaces the inherited one: ```xml <!-- parent --> <properties> <java.version>17</java.version> <skipTests>false</skipTests> </properties> <!-- child overrides just one --> <properties> <java.version>21</java.version> </properties> ``` Effective child: `java.version=21`, `skipTests=false`. ## Plugin configuration merging Plugins are matched by `groupId:artifactId`. Their `<configuration>` is merged element-by-element. By default, **child config wins on conflicts and lists are appended**. You steer this with special attributes: - `combine.children="append"` (default) vs `combine.children="merge"` — how nested lists combine. - `combine.self="override"` — replace the parent's element entirely instead of merging. ```xml <configuration> <arguments combine.self="override"> <argument>--only-this</argument> </arguments> </configuration> ``` Without `override`, child arguments would be *added* to the parent's list, which is a common surprise. ## Dependencies and other lists Dependencies merge by coordinate: a child `<dependency>` with the same `groupId:artifactId` overrides the parent's (e.g. to change scope or version). Otherwise they accumulate. ## Verify, don't guess Always check with: ```bash mvn help:effective-pom -Doutput=effective.xml ``` It shows exactly what Maven resolved after all merging and active profiles.

  • By default, does child plugin configuration replace or merge with the parent's?
    It merges element-by-element, with child values winning on conflicts and list entries appended. Use combine.self="override" to replace instead of merge.
  • If parent sets java.version=17 and child sets 21, what wins?
    21 — the nearest (child) definition wins; other parent properties the child didn't redefine are still inherited.

saying these in an interview costs you the question

  • Assuming child plugin config always fully replaces the parent's (it merges by default)
  • Thinking the Super POM overrides the child
  • Forgetting list configuration is appended unless you set combine.self=override

context