Reproducible Build
A build is reproducible when building the same source the same way produces the same output, byte for byte. The Reproducible Builds project’s definition is precise about what “the same way” includes: “a build is reproducible if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.”
Two words in that sentence do a lot of work. Any party — the point is that someone other than you can check. And specified — the scope is declared rather than universal: “the relevant attributes of the build environment, the build instructions and the source code as well as the expected reproducible artifacts are defined by the authors or distributors.” A claim of reproducibility is a claim about a stated set of outputs under stated conditions.
Verification is mechanical, which is what makes the property useful: reproducibility “is verified by bit-by-bit comparison. This is usually performed using cryptographically secure hash functions.” Either the hashes match or they do not.
What makes two builds differ
Almost nothing on this list is in your source code, which is why the first attempt at a reproducible build is usually surprising. The project’s documentation catalogues the categories; grouped by where they come from, they are:
- Time. Embedded build timestamps, and archive metadata that records modification times. This is common enough to have a standard mitigation, the
SOURCE_DATE_EPOCHconvention. - The machine’s settings. Timezone and locale — a locale can change sort order and therefore the order of anything sorted during the build.
- Paths. The absolute build path leaking into debug information or generated files, so building in a different directory produces a different binary.
- Order. Filesystem iteration order for inputs, and unstable ordering of outputs such as archive entries or hash-map traversal.
- Deliberate variation. Randomness, uninitialized values, and version strings derived from the build environment rather than the source.
The definition treats the environment’s relevant attributes — “dependencies and their versions, build configuration flags and environment variables as far as they are used by the build system (eg. the locale)” — as part of what has to be fixed, and adds one instruction worth following even if you never chase bit-for-bit output: “it is preferable to reduce this set of attributes.” Every input a build depends on is something that can change underneath you without anyone touching the code.
Note the scope of what must match. Artifacts are “executables, distribution packages or filesystem images” and “not usually include build logs or similar ancillary outputs” — logs are expected to differ, and a log containing a timestamp is not a reproducibility failure.
Three levels, and which one you need
Treating this as all-or-nothing is why teams either ignore it or over-invest. It is more useful as three levels answering three different questions.
| Level | The question it answers | Cost |
|---|---|---|
| Recorded provenance | What went into this artifact? | Low — the build platform emits a record |
| Deterministic inputs | Are the inputs I control the same on a rebuild? | Moderate — pin every dependency, version the build environment |
| Bit-for-bit reproducibility | Can someone else verify this binary without trusting me? | High — eliminate every source of variance above |
The first level is formalized by SLSA’s build track, whose lowest level requires the platform to “automatically generate provenance describing how the artifact was built, including: what entity built the package, what build process they used, and what the top-level input to the build were.” Its stated focus is “mistakes, documentation,” and the specification is refreshingly blunt that this level is “trivial to bypass or forge.”
Two limits on what that record answers, and the specification states both. The scope is top-level inputs, not the transitive dependency set — so “what went into this artifact” is answered at the level the build recorded, and identifying everything underneath is a separate artefact (a bill of materials) rather than a consequence of reaching L1. And completeness is not promised at all: “provenance may be incomplete and/or unsigned at L1. Higher levels require more complete and trustworthy provenance.” So the right expectation is that provenance at this level helps an investigation, does not resist an attacker, and does not certify that the record is exhaustive.
The second level is where most application teams should aim, and it is often mistaken for the third. Every dependency is pinned and the build environment is itself a versioned artifact, so the inputs you control are the same on a rebuild and you can answer what changed between two releases.
Resist the step people take next, though: pinning inputs is not a demonstration that behaviour is identical. A build that reads the clock, draws a random value, or fetches a response over the network can produce differing behaviour from the same pinned dependencies and the same image — and differing bytes are how you would have noticed, which is the signal this level gives up. Pinning shrinks the set of uncontrolled inputs rather than enumerating it.
Which changes the standing of a rebuild. “Rebuild and redeploy” is safe when you have either eliminated the uncontrolled inputs or verified that they do not affect behaviour; otherwise the rebuild output is a new artifact and deserves the checks a new artifact gets. That is not an argument against rebuilding — it is the reason the general rule stays “promote the artifact you verified” rather than “rebuild from the same tag,” and the reason the remaining byte differences are worth eliminating when the cost of a silent behaviour change is high. Chasing them purely for third-party verification pays off later, and rarely before.
The third level is what lets a third party rebuild and compare hashes without trusting the builder. It matters most for widely distributed software, for anything where the build machine is part of the threat model, and — usefully — as a way to check the claims of a build platform you do not control.
Reproducibility and provenance are not a sequence
It is tempting to read these as steps on one ladder. They are not. SLSA lists “whether reproducible builds are used” as an implementation choice each ecosystem or organization makes, and its higher levels are about trust in the build platform rather than determinism of output: L2 adds signed provenance from a hosted platform, aimed at “tampering after the build,” and L3 hardens the platform against “tampering during the build.”
The two L3 controls are worth reading as questions about your own pipeline today, because they are concrete and commonly failed. Can one build run influence another — shared caches, a shared working directory, a writable dependency mirror? The requirement is to “prevent runs from influencing one another, even within the same project.” And can a build script read the credentials that sign its own output? The requirement is to “prevent secret material used to sign the provenance from being accessible to the user-defined build steps,” and a pipeline where a test step can print the signing key has a signature that proves nothing.
The two properties also reinforce each other in a specific way the specification notes: signing “may be done during the original build, an after-the-fact reproducible build, or some equivalent system.” A reproducible build lets someone else confirm that the provenance is telling the truth, which is a stronger position than either property alone.
One reassurance about scope: SLSA treats builds “that are built and run on the same machine, such as unit tests” as needing no guarantees at all. The effort belongs on the artifacts you deploy and distribute, not on every build anyone runs.
A last note on terminology, since the word travels badly. This is about build outputs, not about reproducing a bug — a minimal example that reproduces a defect is a different practice with a different purpose. And the reproducibility of a data or model pipeline, where the concerns are seeds, configuration, and checkpoints, is a related idea applied to a different kind of output.
Why any of this matters beyond tidiness is the subject of software supply chain security. The object whose reproducibility is at stake is a build artifact, moved between environments by environment promotion, and how much of this to adopt is worked through in You Tested a Different Binary.
References: Reproducible Builds, Definitions; SLSA v1.2, Build Track Basics (a versioned specification — quotations are from v1.1, checked September 2026).
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
