skip to content

Aggregation vs Inheritance

The aggregator role of listing modules versus the parent role of being inherited, and why one POM commonly plays both. A favorite question because candidates routinely merge the two ideas into one.

on this pageshow

explore

questions

5

Why does an aggregator/parent POM use <packaging>pom</packaging>, and what does it produce?

level: juniorimportance: must knowfreq 55%

answer

  1. pom packaging = no jar, POM is the artifact
  2. required when <modules> present
  3. parent/BOM are pom-packaged
  4. installs only the .pom file
  5. minimal lifecycle, no compile

basics

~20 s

Because it isn't a real artifact like a jar — it only organizes other modules and/or shares config. packaging=pom makes Maven install just the POM file itself (no jar/war), and it is required for any POM with a <modules> section.

solid answer

~40 s

`<packaging>pom</packaging>` tells Maven this project produces **no compiled artifact** — no jar, war, or class output. Its deliverable is the POM file itself, which gets installed/deployed so other projects can reference it (as a parent via inheritance, or as a BOM via import). It is **mandatory** for an aggregator: a POM that lists `<modules>` must be packaging `pom`. It is also the natural packaging for a pure parent POM that only carries shared `<dependencyManagement>`, `<pluginManagement>`, and properties. Because there is nothing to compile, the default lifecycle for pom packaging is minimal — mostly `install`/`deploy` of the POM and processing of any modules. Trying to aggregate with `jar` packaging is a configuration error.

code

xml · 10 lines
xml
<project>
  <groupId>com.acme</groupId>
  <artifactId>acme-parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <modules>
    <module>core</module>
    <module>service</module>
  </modules>
</project>

go deeper

for a junior

Knows the root/parent uses packaging=pom and makes no jar.

for a middle

Knows it is required for <modules> and used for parents/BOMs.

for a senior

Explains lifecycle differences and BOM import vs inheritance use of pom packaging.

for a principal

Decides parent-vs-BOM strategy and what gets published as pom artifacts across the org.

## What packaging means The `<packaging>` element selects which artifact a project produces and which lifecycle bindings run. `jar` (the default) compiles classes and builds a jar; `war` builds a web archive; `pom` builds *nothing executable* — its artifact **is the POM file**. ```xml <project> <groupId>com.acme</groupId> <artifactId>acme-parent</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>core</module> </modules> </project> ``` ## Why aggregators/parents need it Two roles both require `pom` packaging: - **Aggregator:** any POM with a `<modules>` list must be `packaging=pom`. There is no source code to compile at that level; its job is to drive the reactor. - **Parent / BOM:** a POM that exists only to be inherited (or imported via `<scope>import</scope>` for a BOM) ships only its configuration, so it is `pom` packaged. ## What gets produced and stored On `install`/`deploy`, Maven places the POM into the local/remote repository under its coordinates (e.g. `com/acme/acme-parent/1.0.0/acme-parent-1.0.0.pom`). No `.jar` accompanies it. Children resolving `<parent>` or importing the BOM download just this POM. ## Lifecycle differences With `pom` packaging, the default phase bindings are sparse — there is no `compile`/`test-compile`/`package` jar step. Running `mvn install` on a pom-packaged aggregator mainly: builds the modules (reactor) and installs the POM(s). This is why an aggregator build feels like it 'just' iterates over children. ## Common errors - Forgetting `packaging=pom` on a POM that has `<modules>` → build error. - Expecting a jar from the parent directory → there isn't one by design.

  • Can a pom-packaged project also be a BOM?
    Yes. A BOM is a pom-packaged project that defines <dependencyManagement> only; consumers import it with <scope>import</scope> and <type>pom</type> to share managed versions without inheritance.
  • What artifact ends up in ~/.m2 for a pom-packaged module?
    Only the POM file itself (e.g. acme-parent-1.0.0.pom). No jar is produced or installed.

saying these in an interview costs you the question

  • Saying an aggregator can use packaging=jar.
  • Expecting the parent module to produce a runnable/compiled jar.
  • Confusing packaging=pom with producing an empty jar.

context

open as a page

In a Maven multi-module project, what is the difference between aggregation and inheritance, and which POM elements express each?

level: middleimportance: must knowfreq 70%

basics

~20 s

Aggregation means a parent POM lists child <modules> so one build command builds them all. Inheritance means a child declares a <parent> and reuses its config (versions, plugins, dependencies). They are independent concerns that often live in the same POM.

open as a page

When you run a build on an aggregator, in what order are the modules built, and how does the reactor decide?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The reactor builds modules in dependency order, not the order they are listed in <modules>. Maven topologically sorts modules so each is built after the modules it depends on. Listed order is only a tiebreaker.

open as a page

How does Maven resolve a child module's <parent>, and what is the role of <relativePath>?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Maven first looks for the parent POM on disk via <relativePath> (default ../pom.xml), and if not found there falls back to local and remote repositories by coordinates. Setting <relativePath></relativePath> empty forces repository-only lookup.

open as a page

How would you structure a Maven monorepo so multiple teams share configuration but keep module boundaries clean?

level: principalimportance: should knowfreq 30%

basics

~10 s

Use a root POM that is both aggregator (lists modules) and parent (shared config). Put versions in <dependencyManagement>/<pluginManagement>, keep each module focused with explicit sibling dependencies, and avoid cycles so the reactor stays parallelizable.

open as a page