How do you run a multi-module Maven build in parallel, and what does the -T option actually control?
answer
- -T 1C = per core
- -T 4 = fixed threads
- reactor DAG topo-sort
- critical path caps speedup
- plugins must be @threadSafe
basics
~10 sUse 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 sIn 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 linesmvn -T 1C clean install # one thread per CPU core
mvn -T 4 -DskipTests package # fixed 4 threadsgo deeper
Knows -T enables parallel builds and the -T 1C vs -T 4 forms.
Understands the reactor DAG, that independent modules run concurrently, and the C suffix.
Reasons about critical-path limits, thread-safe plugins, and flaky parallel tests before enabling -T in CI.
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