skip to content

How does project.build.outputTimestamp make a Maven archive reproducible, and what values can it take?

level: seniorimportance: must knowfreq 45%

answer

  1. one property -> all packaging plugins
  2. Maven Archiver consumes it
  3. ISO-8601 or epoch seconds
  4. value 1 = derive from SCM commit
  5. stamps entries + sorts order

basics

~10 s

Setting project.build.outputTimestamp gives Maven Archiver a fixed timestamp to stamp on every archive entry instead of the current time, and it sorts entries. It accepts an ISO-8601 instant or Unix epoch seconds.

solid answer

~40 s

`project.build.outputTimestamp` is the standard Maven property that drives reproducibility. When set, Maven Archiver (used by maven-jar-plugin, maven-war-plugin, maven-assembly-plugin, maven-source-plugin, etc.) uses it as the last-modified time for *every* entry in the produced archive instead of the current wall-clock time, and it writes entries in a stable, sorted order. That removes the two big non-determinism sources. The value is either an ISO-8601 instant like `2024-01-01T00:00:00Z` or an integer Unix epoch (seconds). Maven also normalizes related manifest fields. Teams commonly set it from the SCM commit timestamp so each release is deterministic yet meaningful; modern Apache/Spring parent POMs accept a special value (e.g. `1`) that resolves the commit date automatically in CI. One property propagates through all archiving plugins, so you rarely configure plugins individually.

code

bash · 1 line
bash
mvn -Dproject.build.outputTimestamp=$(git log -1 --format=%ct) clean package

go deeper

for a junior

Knows there is a property that fixes archive timestamps.

for a middle

Knows the accepted value formats and that it normalizes timestamps and ordering.

for a senior

Knows it is consumed by shared Maven Archiver so one setting covers all packaging plugins, and can derive it from SCM.

for a principal

Standardizes the property in the org BOM/parent and combines it with verification gates, knowing its scope and limits.

## The single lever Maven exposes one well-known property: **`project.build.outputTimestamp`**. It lives under `<properties>` in your POM (or a parent/BOM). Setting it switches Maven from 'stamp the current time on each entry' to 'stamp this fixed time on every entry, and order entries deterministically.' ## What reads it The property is consumed by **Maven Archiver**, the shared component behind the packaging plugins: - `maven-jar-plugin` - `maven-war-plugin` - `maven-ejb-plugin` - `maven-source-plugin` - `maven-assembly-plugin` - `maven-shade-plugin` (honors it too) Because they all share Maven Archiver, **one property** makes all of them reproducible — you don't normally configure each plugin. ## Accepted values - **ISO-8601 instant:** `2024-01-01T00:00:00Z` (the most common, human-readable form). - **Unix epoch seconds:** an integer like `1704067200`. - **Special derive-from-SCM value:** recent parent POMs (Apache parent, Spring Boot starter parent) support setting it to `1`, which tells the `git-commit-id` / SCM tooling to substitute the commit timestamp. This makes each release deterministic but tied to its real commit. ## What it normalizes - Per-entry **last-modified timestamps** -> all set to the fixed value. - **Entry ordering** -> sorted, stable across OS/filesystem. - File **permissions/UID/GID** in the archive are normalized. ## Example ```xml <project> <properties> <project.build.outputTimestamp>2024-01-01T00:00:00Z</project.build.outputTimestamp> </properties> </project> ``` Deriving it from git in CI: ```bash # epoch seconds of the last commit mvn -Dproject.build.outputTimestamp=$(git log -1 --format=%ct) clean package ``` ## Caveat: not everything is covered `outputTimestamp` fixes the *archiving* layer. Other plugins that generate content (some code generators, `Build-Jdk-Spec` differences, `Implementation-Build` git hashes if you inject them) can still introduce variance. Verify with `artifact:check-buildplan`.

  • Why is it enough to set this once rather than per plugin?
    All packaging plugins delegate to the shared Maven Archiver component, which reads the property, so a single property propagates to jar/war/assembly/source/shade outputs.
  • What does the value '1' do in modern parent POMs?
    It signals the parent's SCM/git-commit-id wiring to resolve the property to the actual commit timestamp, so each release is deterministic and tied to its commit.

saying these in an interview costs you the question

  • Thinking you must configure each plugin's timestamp separately.
  • Believing outputTimestamp alone guarantees full reproducibility regardless of other generators.
  • Confusing it with maven.build.timestamp (which is the volatile current time used in filtering).

context