Build performance and reproducibility

Maven · Expert · 12 min

Slow and non-deterministic builds hurt CI and trust; Maven has specific remedies for both.

Maven builds are often slower than they need to be. Levers, roughly in order of payoff:

  • Parallel reactor: -T 1C builds independent modules concurrently (one thread per core). Plugins must be marked thread-safe; Maven warns about the rest.
  • mvnd (the Maven Daemon): a long-running, warmed-up JVM with a native client that cuts startup from seconds to milliseconds and runs modules in parallel by default. Maven 4 integrates these ideas.
  • maven-build-cache-extension: caches module outputs keyed by inputs (sources, POM, dependencies), locally or in a remote store, so unchanged modules are restored rather than rebuilt. Add it in .mvn/extensions.xml and tune maven-build-cache-config.xml.
  • Skip what you don't need: -DskipTests for local packaging, -o offline when the local repo is warm, -pl/-am for a subset, -Dmaven.javadoc.skip.
  • Reduce plugin executions: enforcer, checkstyle and site generation can run in a separate CI job. Use -Dmaven.test.redirectTestOutputToFile=true and Surefire forking tuned for your machine.
  • Check what's slow with -Dorg.slf4j.simpleLogger.showDateTime=true or a profiler extension (maven-profiler).

Reproducible builds: with project.build.outputTimestamp set (<project.build.outputTimestamp>2026-01-01T00:00:00Z</project.build.outputTimestamp>, updated at release), the jar, source and javadoc plugins normalize file timestamps and ordering so the same inputs give byte-identical artifacts. Pin every plugin version, avoid version ranges and LATEST, and use the dependency lock approach of a BOM plus enforcer requireUpperBoundDeps/dependencyConvergence to keep resolution stable. artifact:compare (maven-artifact-plugin) verifies reproducibility against a reference build.

CI tips: cache ~/.m2/repository, use the wrapper, pass --batch-mode and --no-transfer-progress.

Example

# .mvn/maven.config  (defaults applied to every mvn invocation in this repo)
--batch-mode
--no-transfer-progress
-T 1C

# .mvn/extensions.xml
# <extensions>
#   <extension>
#     <groupId>org.apache.maven.extensions</groupId>
#     <artifactId>maven-build-cache-extension</artifactId>
#     <version>1.2.0</version>
#   </extension>
# </extensions>

# pom.xml property for reproducible archives
# <project.build.outputTimestamp>2026-01-01T00:00:00Z</project.build.outputTimestamp>

mvnd verify                                  # Maven Daemon: warm JVM, parallel by default
mvn -o -pl api -am -DskipTests package       # offline, subset of modules
mvn verify -Dmaven.build.cache.enabled=true  # with the cache extension installed
mvn clean verify artifact:compare            # check the build is reproducible
# CI: cache ~/.m2/repository between runs; always use ./mvnw

Remember

  • -T 1C and mvnd parallelize and remove JVM startup cost
  • The build cache extension restores unchanged modules
  • project.build.outputTimestamp plus pinned versions give byte-identical builds
  • Cache ~/.m2 and use --batch-mode in CI

Watch out for

  • Enabling -T with plugins that aren't thread-safe and getting intermittent build failures.

Check yourself

  1. What does project.build.outputTimestamp enable?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: maven.apache.org/guides/mini/guide-reproducible-builds.html