Safeguard
Developer Tools•

Are Gradle jar and zip files reproducible by default?

From Gradle 9.0.0 archive tasks are reproducible by default: fixed order, timestamps and permissions. On older versions you set three properties yourself.

Safeguard Security Team
4 min read

From Gradle 9.0.0, yes. Archive tasks such as Jar and Zip produce reproducible output by default, with deterministic file order, fixed timestamps and fixed permissions. On older Gradle versions you can get the same effect by setting file timestamp, file order and permission options on each archive task.

What the Gradle docs say it now does

The Gradle user guide explains why this matters. The order of files inside a ZIP, TAR, JAR, WAR or EAR can change each time it is built, and files on disk can carry different timestamps or permissions depending on the environment.

Starting with Gradle 9.0.0, tasks that extend AbstractArchiveTask produce archives where:

  • file order is deterministic,
  • files have fixed timestamps, with exact values depending on the archive type,
  • directories have fixed permissions of 0755,
  • files have fixed permissions of 0644.

You can still customise permissions or timestamps while keeping the archive reproducible. If a script needs the executable bit, set that explicitly instead of reverting to filesystem permissions.

What to do on an older Gradle

The Reproducible Builds JVM page documents the pre Gradle 9 approach. Gradle supported reproducible archives since version 3.4, and you opt in per task:

tasks.withType<AbstractArchiveTask>().configureEach {
    isPreserveFileTimestamps = false
    isReproducibleFileOrder = true
}

That page also suggests setting directory and file permissions to ignore the system umask, and keeping the executable bit by checking the owner execute permission. Treat that as a pattern to adapt, then test it.

Reverting by accident

Gradle 9 lets you revert each aspect. Setting the preserve timestamps option to true, turning reproducible file order off, or calling the filesystem permissions method each brings back an environment dependent behaviour. There is also a project property to use filesystem permissions across all archive tasks.

Search your build scripts for those settings. If one exists for a good reason, such as permissions managed by version control, record it in a comment so a reviewer knows it was deliberate.

Other Gradle traps

Reproducible archives fix packaging. They do not fix everything.

Source of variationWhat to do
Properties files written with java.util.Properties.storeSet the java.properties.date system property to a fixed value
Default charset on Java 17 and olderSet file.encoding to UTF-8
Locale dependent outputSet user.language and user.country consistently
Generated pom.xml edited with withXmlConfigure it on the publication, not on the generate task, so element order is stable
Dynamic or changing dependency versionsLock them so each build resolves the same artifacts

The JVM page lists the first four and gives gradle.properties examples for the charset and locale settings.

A quick test

Build twice from clean checkouts, ideally on different machines, and compare checksums of the jar. If they differ, run diffoscope on the two jars and read the first difference. Do not assume the Gradle default covers a custom task that writes its own files.

Quick check

Do I need to change anything if I use Gradle 9?

Not for basic archive reproducibility, but check for settings that revert it, and handle properties files, locale and changing dependencies yourself.

Does a reproducible jar mean my dependencies are pinned?

No. Dependency versions are a separate input. Pin or lock them so each build uses the same artifacts.

Safeguard's SBOM and dependency scanning, generally available, lists the exact components your artifacts contain. The free scan at gold.safeguard.sh/scan is a quick way to see your dependency list.

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.