skip to content

How do combine.children and combine.self control how a child POM's plugin configuration merges with an inherited one?

level: seniorimportance: should knowfreq 35%

answer

  1. default = recursive merge, lists append
  2. combine.children: merge | append (children of element)
  3. combine.self: merge | override | remove (the element)
  4. override = ignore parent, reset list
  5. verify with help:effective-pom

basics

~20 s

By default Maven merges inherited and child plugin config, appending list items. The combine.children attribute controls list merging (merge vs append), and combine.self controls whether the child element merges with, overrides, or removes the parent's element.

solid answer

~40 s

Maven merges plugin `<configuration>` from parent/pluginManagement with the child's using XML merge rules. For list-like elements, the default behavior **appends** the parent's child items to the child's. You override this with two attributes placed on a configuration element: `combine.children` (values `merge` or `append`) governs how the *child elements of that element* combine — `append` concatenates lists; `merge` matches by element and merges. `combine.self` (values `merge`, `override`, `remove`) governs the element *itself* — `override` replaces the inherited element entirely (ignore parent), `merge` (default) blends them, and `remove` deletes the inherited element. These let you, for instance, replace an inherited `<excludes>` list rather than accumulating onto it. They are essential when a parent POM sets defaults you must fully override in one module.

code

xml · 10 lines
xml
<configuration>
  <!-- replace inherited excludes entirely -->
  <excludes combine.self="override">
    <exclude>**/IntegrationTest.java</exclude>
  </excludes>
  <!-- append to inherited systemProperties -->
  <systemPropertyVariables combine.children="append">
    <env>ci</env>
  </systemPropertyVariables>
</configuration>

go deeper

for a junior

Aware that parent and child plugin config get merged.

for a middle

Knows lists append by default and that combine attributes exist.

for a senior

Correctly picks combine.self=override/remove vs combine.children=append/merge and verifies via effective-pom.

for a principal

Sets conventions to minimize override complexity and reviews merge behavior across a large module hierarchy.

## Why merging exists When a module activates a plugin that also has configuration in a parent POM or in `<pluginManagement>`, Maven combines both `<configuration>` trees. By default this is a recursive merge, and for repeated (list) elements the parent's items are **appended** to the child's. Usually that is what you want — but sometimes you need to *replace* or *remove* the inherited values. The `combine.*` attributes give you that control. ## combine.children — controls the children of an element Put it on the *container* element whose children are lists: - `combine.children="append"` — concatenate parent items and child items (may produce duplicates). This is effectively the default for list-valued elements. - `combine.children="merge"` — merge element-by-element rather than blindly appending. ```xml <configuration> <excludes combine.children="append"> <exclude>**/Generated*.java</exclude> </excludes> </configuration> ``` ## combine.self — controls the element itself Put it on the element you want to control: - `combine.self="merge"` — default; blend this element with the inherited one. - `combine.self="override"` — **ignore the inherited element entirely** and use only the child's content. This is the key one for "reset the parent's list." - `combine.self="remove"` — delete the inherited element so it disappears from the effective POM. ```xml <configuration> <!-- completely replace the parent's excludes, don't append --> <excludes combine.self="override"> <exclude>**/ManualOnly*.java</exclude> </excludes> </configuration> ``` ## Verifying the result The merged configuration is part of the **effective POM**. Run `mvn help:effective-pom` to see exactly what config a plugin will receive after inheritance and combine attributes are applied — the authoritative way to debug surprising merges. ## When you reach for these - A parent sets `<argLine>` or an `<excludes>` list and one module needs a *different* set, not an additive one → `combine.self="override"`. - You want to drop an inherited config element entirely → `combine.self="remove"`. - You want explicit, predictable list behavior across the reactor → set `combine.children` deliberately. ## Caveat These attributes are easy to misuse and create configs that are hard to reason about. Prefer keeping shared defaults minimal so most modules need no overrides; use `combine.*` surgically and confirm with `help:effective-pom`.

  • A parent sets <excludes> and your module needs a totally different list, not the union. What attribute do you use?
    combine.self="override" on the child <excludes> element, so the inherited list is ignored and only the child's entries apply.
  • How do you confirm what config a plugin actually receives after merging?
    Run mvn help:effective-pom; it shows the fully merged effective POM including the result of all combine attributes and inheritance.
  • What is the difference between combine.children and combine.self?
    combine.children controls how the child elements (lists) of an element combine (append vs merge); combine.self controls the element itself (merge, override the inherited element, or remove it).

saying these in an interview costs you the question

  • Thinking inherited and child lists always replace (they append by default)
  • Confusing combine.children with combine.self
  • Believing override merges rather than fully replacing
  • Not knowing help:effective-pom can verify the merge

context