When you run a build on an aggregator, in what order are the modules built, and how does the reactor decide?
answer
- reactor = topological sort, not list order
- core before service automatically
- -pl select, -am upstream, -amd downstream
- -rf resume after failure
- cycles are an error
basics
~20 sThe 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.
solid answer
~50 sRunning a goal on an aggregator triggers a **reactor** build. Maven gathers all modules in `<modules>` (plus any nested aggregators recursively), reads their inter-module dependencies, and performs a **topological sort** so that a module is always built after the modules it depends on. Therefore the order in `<modules>` is largely cosmetic — it only breaks ties between otherwise-independent modules. A `core` module depended on by `service` is built first even if listed last. If you depend on a sibling, you reference it by its Maven coordinates (groupId/artifactId/version); the reactor substitutes the just-built artifact instead of pulling from the repository. Useful flags: `-pl` (project list) to build specific modules, `-am` (also make) to additionally build their upstream dependencies, `-amd` (also make dependents) for downstream, `-rf` (resume from) to restart at a module after a failure, and `-T` for parallel reactor builds across independent modules.
code
bash · 5 lines# build only 'service' plus everything it depends on, in parallel
mvn -pl service -am -T 1C package
# resume the reactor from 'web' after a mid-build failure
mvn -rf web installgo deeper
Knows the root build builds all modules; unaware of ordering details.
Understands dependency-based ordering and basic -pl usage.
Uses -am/-amd/-rf/-T deliberately; reasons about reactor for CI optimization.
Designs module graph to be acyclic and parallelizable; defines CI strategy using reactor selection flags at scale.
## The reactor The **reactor** is Maven's name for the set of modules collected for a single multi-module build and the engine that orders and runs them. When you invoke a phase like `mvn package` on an aggregator, the reactor: 1. **Collects** every module from `<modules>`, descending recursively into nested aggregators. 2. **Reads dependencies** between those modules (sibling dependencies declared by coordinates). 3. **Topologically sorts** them: each module is scheduled after all modules it depends on. 4. **Builds** them in that order, feeding each just-built artifact into the reactor so dependents use the fresh output rather than `~/.m2`. ## Why <modules> order doesn't dictate build order If `service` depends on `core`, `core` builds first regardless of list position. The declared order only matters as a deterministic tiebreaker among modules with no dependency relationship. Relying on list order for correctness is a misconception. ## Sibling references A module depends on a sibling exactly like any other dependency: ```xml <dependency> <groupId>com.acme</groupId> <artifactId>core</artifactId> <version>1.0.0</version> </dependency> ``` During a reactor build, Maven resolves `core` to the in-reactor module output, enabling true incremental monorepo builds. ## Reactor flags (CLI) - `-pl core,service` — build only these projects. - `-am` (--also-make) — also build upstream deps of the selected projects. - `-amd` (--also-make-dependents) — also build downstream dependents. - `-rf service` (--resume-from) — resume the reactor starting at a module (great after a mid-build failure). - `-T 1C` / `-T 4` — parallel build using N threads or N-per-core, across independent modules. - `-fae` / `-ff` — fail-at-end vs fail-fast. ## Practical implications - A cyclic dependency between modules is an **error** — the reactor cannot topologically sort a cycle. - For CI speed, `-pl ... -am` builds only what changed plus what it needs. - After a flaky failure, `-rf` avoids rebuilding everything from scratch.
- What happens if two modules depend on each other?The reactor cannot topologically sort a dependency cycle and the build fails. You must break the cycle, often by extracting shared code into a third module.
- How would you rebuild only a changed module and its consumers in CI?Use mvn -pl changed-module -amd ... to build the module plus its dependents (also-make-dependents), or -am to build it plus its upstream dependencies.
saying these in an interview costs you the question
- Saying modules build strictly in <modules> declaration order.
- Claiming sibling deps are pulled from the remote repo during a reactor build (they use in-reactor output).
- Thinking the reactor can handle circular module dependencies.