skip to content

Reactor Build Order

How the reactor topologically sorts modules by their dependency edges rather than by the order they are listed, and resolves sibling artifacts straight from target/. Asked because reordering <modules> to 'fix' a build is a classic misconception.

on this pageshow

explore

questions

5

In a Maven multi-module build, what determines the order in which the reactor builds the modules?

level: juniorimportance: must knowfreq 70%

answer

  1. topological sort
  2. dependency edges not <modules> order
  3. parent + plugins count as edges
  4. cycle => build fails
  5. reactor summary shows order

basics

~20 s

Maven's reactor builds modules in dependency order, not in the order they are listed in <modules>. It looks at each module's <dependency> entries and builds a needed module before the one that depends on it.

solid answer

~40 s

The reactor (Maven's multi-module engine) computes a topological sort of the modules based on inter-module dependency edges. It scans every module's <dependency> declarations, plus parent/plugin references, finds which other reactor modules each one depends on, and orders the build so a dependency is always built before its consumer. The order in the aggregator POM's <modules> list is only a starting hint and a tiebreaker when modules are independent; it does NOT dictate build order. So if module-app depends on module-core, core builds first even if app is listed first. A cyclic dependency between modules makes the graph unsortable and Maven fails with a cycle error.

code

xml · 8 lines
xml
<project>
  <packaging>pom</packaging>
  <modules>
    <module>app</module>
    <module>core</module>
  </modules>
</project>
<!-- If app depends on core, Maven builds core BEFORE app -->

go deeper

for a junior

Knows the reactor builds dependencies before dependents and that <modules> order isn't authoritative.

for a middle

Can explain that edges come from <dependency>, <parent>, and plugins, and that the result is a topological sort.

for a senior

Understands tiebreaking by declaration order, cycle failures, and how missing declared edges cause subtle ordering bugs.

for a principal

Designs module graphs to stay acyclic and shallow, and treats explicit dependency declarations as the contract that keeps reactor ordering deterministic.

## What the reactor is The **reactor** is the part of Maven that handles a build spanning multiple modules. When you run `mvn` against an **aggregator POM** (a POM with `<packaging>pom</packaging>` and a `<modules>` block), Maven collects all listed modules into one build session, decides an order, and builds them in sequence. ## Build order = topological sort, not declaration order The single most important fact: **the order of `<module>` entries does NOT decide build order.** Maven builds a directed graph where an edge points from a module to each other reactor module it depends on, then performs a **topological sort** — every module is built only after all the modules it depends on are built. Maven derives the edges from: - `<dependency>` entries that reference another reactor module's GAV (groupId/artifactId/version) - The `<parent>` reference if the parent is also in the reactor - Plugins (and their dependencies) that are themselves reactor modules The `<modules>` list order is used only as a **stable tiebreaker** for modules that have no dependency relationship between them. ## Why this matters It means you can list modules in any convenient order (often alphabetical) and Maven still gets it right. It also means a missing `<dependency>` edge — e.g. relying on classpath leakage rather than a real declared dependency — can produce a wrong order or flaky builds. ## Cycles fail the build If module A depends on B and B depends on A (directly or transitively), the graph has a **cycle**, no valid topological order exists, and Maven aborts with an error like "The projects in the reactor contain a cyclic reference." ## Example ```xml <!-- aggregator pom.xml --> <project> <packaging>pom</packaging> <modules> <module>app</module> <!-- listed first --> <module>core</module> <!-- listed second --> </modules> </project> ``` If `app/pom.xml` declares a dependency on `core`, Maven still builds **core first, then app**, ignoring the listing order. ## Inspecting the order Run the build with `-X` (debug) or just read the reactor summary at the end of any multi-module build — Maven prints the modules in the exact order it built them.

  • If I reorder the <modules> list, will the build order change?
    No — declaration order only breaks ties between independent modules; real build order comes from the dependency graph.
  • What happens if two modules depend on each other?
    The graph has a cycle, no topological order exists, and Maven fails with a cyclic reference error. You must break the cycle, often by extracting shared code into a third module.

Like cooking a recipe: you don't chop onions in alphabetical order, you do prep steps in the order the later steps need them.

saying these in an interview costs you the question

  • Saying modules build in the order they appear in <modules>
  • Believing you must manually order modules so dependencies come first
  • Thinking parent POM references don't affect ordering

context

open as a page

When module-app depends on module-core in the same reactor, how does Maven resolve module-core's classes without you running mvn install first?

level: middleimportance: must knowfreq 55%

basics

~10 s

Within a single reactor build, Maven resolves a dependency module directly from its freshly built target/ output (or in-memory artifact) instead of the local ~/.m2 repository, so you don't need a separate mvn install.

open as a page

What causes a reactor cyclic dependency error, and how do you resolve it architecturally?

level: seniorimportance: should knowfreq 35%

basics

~20 s

A cycle happens when module A depends on B and B depends (directly or transitively) back on A. The reactor can't topologically sort a cyclic graph, so it fails. Fix it by extracting shared code into a new third module both can depend on.

open as a page

How do -pl, -am, -amd, and -rf control which modules the reactor builds, and when would you use each?

level: seniorimportance: should knowfreq 45%

basics

~10 s

-pl picks specific modules (project-list). -am also builds their upstream dependencies (also-make). -amd also builds downstream dependents (also-make-dependents). -rf resumes from a given module (resume-from) after a failure.

open as a page

How do reactor failure behavior (-ff/-fae/-fn) and parallel builds (-T) interact with reactor ordering?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Failure flags decide what happens after a module fails: -ff (fail-fast, default) stops immediately, -fae (fail-at-end) keeps building independent modules then reports all failures, -fn (fail-never) ignores failures. -T runs independent modules in parallel threads while still honoring dependency order.

open as a page