skip to content

Build Performance

Making Maven faster: parallel reactor builds with -T, the mvnd daemon, offline mode, the build cache extension, and measuring where the time actually goes. A practical question that separates people who tuned a build from people who only waited on one.

on this pageshow

explore

questions

5

How do you run a multi-module Maven build in parallel, and what does the -T option actually control?

level: middleimportance: must knowfreq 65%

answer

  1. -T 1C = per core
  2. -T 4 = fixed threads
  3. reactor DAG topo-sort
  4. critical path caps speedup
  5. plugins must be @threadSafe

basics

~10 s

Use the -T flag, e.g. mvn -T 4 install for 4 threads or mvn -T 1C install for one thread per CPU core. Maven builds independent modules of the reactor concurrently.

solid answer

~40 s

In a multi-module build the 'reactor' computes a dependency graph of modules and topologically sorts them. `-T` enables the parallel builder, which runs modules that have no pending inter-dependencies on separate threads. `-T 4` means a fixed 4 threads; `-T 1C` means 1 thread per available core (so `1.5C`, `2C` scale with CPU). Speedup is bounded by the graph's critical path — a deep linear dependency chain barely parallelizes, while a wide flat set of leaf modules scales well. Caveats: plugins and tests must be thread-safe, shared mutable state or non-isolated integration tests can break, and console output interleaves. Always verify the build is still correct (and reproducible) before committing to parallel CI runs.

code

bash · 2 lines
bash
mvn -T 1C clean install        # one thread per CPU core
mvn -T 4 -DskipTests package   # fixed 4 threads

go deeper

for a junior

Knows -T enables parallel builds and the -T 1C vs -T 4 forms.

for a middle

Understands the reactor DAG, that independent modules run concurrently, and the C suffix.

for a senior

Reasons about critical-path limits, thread-safe plugins, and flaky parallel tests before enabling -T in CI.

for a principal

Shapes module graphs to be wide/parallelizable, sets org-wide -T policy, and weighs it against mvnd and build caching.

## What the reactor is When you build a project with several `<module>` entries, Maven treats them as a single 'reactor'. It reads every module's POM, builds a directed acyclic graph (DAG) of inter-module dependencies, and produces a build order via topological sort so a module is always built after the modules it depends on. ## Serial vs parallel By default the reactor builds one module at a time, in that sorted order. The `-T` (`--threads`) option switches on the *parallel builder*: it walks the same DAG but starts any module whose dependencies are already finished on a free worker thread. Independent branches of the graph run at the same time. ## Forms of -T - `-T 4` — a fixed pool of 4 worker threads. - `-T 1C` — one thread *per CPU core* (the `C` suffix multiplies by `Runtime.availableProcessors()`). `-T 1.5C`, `-T 2C`, etc. are valid. - `-T 0.5C` — half the cores, useful to leave headroom. ## What limits the speedup Parallelism is capped by the *critical path* of the dependency graph. If module A→B→C→D form a chain, they must run sequentially no matter how many threads you give. A 'wide' project (many leaf modules depending on one shared core) parallelizes much better. Amdahl's law applies: the serial portion (the longest chain) sets the floor. ## Correctness caveats - Plugins must be thread-safe; most modern core plugins are annotated `@threadSafe`. Maven warns about non-thread-safe plugins under `-T`. - Tests that bind to fixed ports, share files/databases, or use static singletons can collide across modules. - Log output from concurrent modules interleaves, making failures harder to read. ```bash # one thread per core across the whole reactor mvn -T 1C clean install # fixed 4 threads, skip tests for a fast compile check mvn -T 4 -DskipTests package ``` Always confirm a parallel build produces the same artifacts as a serial one before relying on it in CI.

  • Why might -T 8 give almost no speedup on some projects?
    Because the modules form a long linear dependency chain; the critical path is serial, so extra threads sit idle. Wide, shallow graphs parallelize; deep chains do not.
  • What does the 'C' suffix mean in -T 2C?
    It multiplies by the number of available processor cores, so 2C = 2 threads per core. A plain integer like -T 4 is an absolute thread count.

Like a kitchen: independent dishes cook on separate burners at once, but a sauce that must reduce before plating still gates the dependent steps no matter how many cooks you add.

saying these in an interview costs you the question

  • Saying -T sets parallel threads within a single module (it parallelizes across modules, not within one)
  • Claiming more threads always means faster (ignores the critical path / thread-unsafe plugins)
  • Confusing -T with -o (offline) or with forking test JVMs

context

open as a page

Explain the -o (offline) option and the difference between --fail-fast and --fail-at-end in a reactor build.

level: juniorimportance: should knowfreq 45%

basics

~20 s

-o builds offline using only the local repository, with no network access (faster, deterministic, but fails if something is missing). --fail-fast (default) stops at the first failed module; --fail-at-end keeps building independent modules and reports all failures at the end.

open as a page

How would you profile a slow Maven build to find where the time goes, especially in dependency downloads?

level: middleimportance: should knowfreq 30%

basics

~10 s

Use a profiling extension like maven-profiler or -Dmaven.profiler style timing, and check -X (debug) logs to see per-plugin/goal durations. For downloads, watch resolution logs, point at a fast mirror/Nexus, and pre-cache with dependency:go-offline.

open as a page

What is mvnd (the Maven Daemon) and why can it be faster than plain mvn?

level: seniorimportance: should knowfreq 35%

basics

~10 s

mvnd runs Maven inside a long-lived background daemon (JVM) that stays warm between builds. It avoids repeated JVM startup and lets the JIT-compiled, class-loaded state be reused, so repeated builds start faster.

open as a page

What does the maven-build-cache-extension do, and how does it decide whether to skip rebuilding a module?

level: seniorimportance: nice to knowfreq 20%

basics

~20 s

It caches the outputs of each module keyed by a hash of that module's inputs (source files, POM, dependencies, plugin config). If the hash matches a prior build, Maven restores the cached output (e.g. the jar) instead of recompiling and re-running goals.

open as a page