skip to content

Compare core extensions (.mvn/extensions.xml) versus build extensions (<build><extensions>): when does each load, and why does it matter?

level: principalimportance: nice to knowfreq 18%

answer

  1. .mvn = bootstrap, before POM parse
  2. <build> = during parsed-project build
  3. core realm vs project extension realm
  4. core: polyglot/smart-builder; build: wagon/packaging
  5. commit .mvn for reproducibility

basics

~10 s

Core extensions in .mvn/extensions.xml load before the POM is read, so they can change project loading itself. Build extensions in <build><extensions> load later, while building an already-parsed project, so they're limited to build-time machinery.

solid answer

~40 s

Both inject components into Maven's runtime, but the timing and classloader differ. Core extensions (.mvn/extensions.xml, Maven 3.3.1+) load during Maven's bootstrap — before any POM is parsed — and join the Maven core realm, so they can replace model readers (polyglot), swap the build sequencer (smart builders), or alter project discovery. Build extensions (<build><extensions>) load once the project model exists, contribute things like wagons, custom packaging/lifecycle, and live in the project's extension realm. The practical consequences: anything that must influence how the project itself is read or sequenced must be a core extension; anything that just augments the build of a normally-parsed project can be a build extension. Core extensions also apply to the whole reactor from the directory they sit in and must be committed so every checkout is reproducible.

code

bash · 5 lines
bash
# core extensions live here, loaded before the POM:
#   project-root/.mvn/extensions.xml
# build extensions live in the POM:
#   <build><extensions><extension>...</extension></extensions></build>
mvn -X validate   # use debug output to see extension realms being created

go deeper

for a junior

Knows there are two places to declare extensions.

for a middle

Knows core extensions load earlier than build extensions.

for a senior

Can map specific use cases to the right mechanism and explain the realm/timing difference.

for a principal

Sets org policy: which extensions are allowed, ensures .mvn is committed, prefers least-powerful mechanism for reproducible, reviewable builds.

## Two extension entry points Maven wires components (Sisu/Plexus) into **classloader realms**. Extensions add components, but *when* they load and *which realm* they join determines what they can do. ### Core extensions — `.mvn/extensions.xml` - Introduced in Maven **3.3.1**. - Located in the project root's `.mvn/` directory. - Loaded during **bootstrap**, *before any POM is parsed*, into a realm close to the Maven core. - Can therefore influence **project loading and sequencing itself**: custom `ModelReader` (polyglot), `BuildListener`/lifecycle participants, replacement build sequencers (Takari smart builder), provisioning extensions. ```xml <!-- .mvn/extensions.xml --> <extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0"> <extension> <groupId>fr.jcgay.maven</groupId> <artifactId>maven-profiler</artifactId> <version>3.3</version> </extension> </extensions> ``` ### Build extensions — `<build><extensions>` - Declared in the **POM**, so the POM is already parsed when they load. - Loaded into a **project-scoped extension realm** during the build. - Suited to things that operate within a normally-loaded project: **wagons** (transport), **custom packaging + LifecycleMapping**, ArtifactHandlers. ```xml <build> <extensions> <extension> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ftp</artifactId> <version>3.5.3</version> </extension> </extensions> </build> ``` ## Why the distinction matters | Concern | Core ext (.mvn) | Build ext (<build>) | |---|---|---| | Load time | Before POM parse (bootstrap) | During build of parsed project | | Realm | Near Maven core | Project extension realm | | Can change model reading | Yes (polyglot) | No | | Can replace build sequencer | Yes (smart builder) | No | | Typical use | polyglot, profilers, smart builder | wagon, packaging, lifecycle | | Scope | The reactor rooted at that dir | The declaring project | ## Governance / reproducibility - `.mvn/extensions.xml` (and `.mvn/maven.config`/`jvm.config`) should be **committed** so every developer and CI runs the identical machinery — otherwise builds diverge. - Core extensions affect the whole multi-module reactor invoked from that directory, making them a powerful but blunt instrument; review them carefully. - Prefer the least-powerful mechanism: use a build extension if it suffices, reserve core extensions for things that genuinely need early loading.

  • Why should .mvn/extensions.xml be committed to version control?
    So every checkout and CI run loads the same core machinery; otherwise builds become non-reproducible across machines.
  • Can a build extension replace Maven's model reader for polyglot?
    No — it loads after the POM is parsed, too late. Model readers must be core extensions.
  • Which extension type can swap the reactor's build sequencer (e.g. Takari smart builder)?
    A core extension in .mvn/extensions.xml, because it loads early enough to influence sequencing.

saying these in an interview costs you the question

  • Claiming both load at the same time / are interchangeable.
  • Putting a polyglot or smart-builder extension in <build><extensions>.
  • Leaving .mvn/extensions.xml uncommitted and assuming builds stay reproducible.

context