Safeguard
Developer Tools•

How do you make a Maven build reproducible?

Set project.build.outputTimestamp, upgrade plugins, and test with artifact:compare. Maven 3.10.0 and 4.0.0-beta-5 turn reproducible mode on by default.

Safeguard Security Team
4 min read

Set the project.build.outputTimestamp property in your pom.xml, upgrade plugins to reproducible versions, and test with the compare goal of the maven-artifact-plugin. Starting with Maven 3.10.0 and 4.0.0-beta-5, reproducible mode is active by default, though setting your own value remains useful for overriding the inherited one.

The three setup steps

Maven's own guide says there is no Maven version prerequisite, because everything happens at plugin level.

  1. Upgrade your plugins to reproducible versions. Run mvn artifact:check-buildplan to see which plugins need upgrading.
  2. Add the output timestamp property:
<properties>
  <project.build.outputTimestamp>2023-01-01T00:00:00Z</project.build.outputTimestamp>
</properties>
  1. Rebuild and compare, as described below.

The guide says this gets the output mostly reproducible. Keep the value in the pom or parent pom so every module uses the same one, and update it when you cut a release if you want the artifact date to reflect that release.

Test it locally

The guide gives a simple two build test:

mvn clean install
mvn clean verify artifact:compare

The first command builds and installs. The second rebuilds without installing and checks against the previous install. Maven is explicit that this local test does not prove a third party can reproduce your build, since environment leaks such as username or current directory may remain. It does catch the basic problems, such as timestamps.

For a real check, rebuild from a different setup. Containers can make that easier. For releases staged in a remote repository, someone else can run verify with artifact:compare against the staging location.

If something still differs

The guide recommends this loop:

  • Use diffoscope on the two outputs. The artifact:buildinfo goal prints a command with the file paths.
  • Work out which plugin produced the unstable output.
  • Check whether a reproducible version of that plugin exists. If not, open an issue with the plugin maintainers.

Other things the guide warns about

Several habits make Maven builds unstable.

HabitWhy it matters
Version ranges in dependenciesThe same build can resolve different artifacts on different days
Building on Windows and UnixDifferent newlines can change outputs
Using only the major version of the JDKDifferent minor builds can produce different results

The guide also points to Reproducible Central, a list of project releases that were checked by rebuilding independently from the reference build published in Maven Central. If you publish a library, being on that list is a visible signal that others can verify your releases.

Pin what the build pulls in

Version ranges are the most common reason a Maven build changes without a code change. Replace ranges with exact versions, and review any snapshot dependency, because a snapshot can resolve to a different artifact tomorrow. Keep the JDK identical too, including the minor version, by using the same container image or toolchain on every build machine.

When you change a version on purpose, make that its own commit, so the diff between two release artifacts maps to a change you can name.

A reproducible jar is a statement about how the jar was built. It does not say the code or the dependencies are free of vulnerabilities. Keep scanning dependencies as you would anyway.

Safeguard's dependency scanning and SBOM generation are generally available, and the free scan at gold.safeguard.sh/scan covers repository dependencies.

Try it yourself

Click through the demo and look at how each dependency is listed with its version, which is the list you pin.

Click through it at your own pace, or open it full screen.

Quick check

Does artifact:compare prove my build is reproducible?

No. It shows two builds on your setup match. Environment leaks can still differ on another machine.

Do I still need the timestamp property on new Maven versions?

It is useful if you want to override the inherited default value.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.