Immutable Artifacts: Build Once, Promote Across Environments
Stop rebuilding in every environment. Build a versioned artifact once in CI and promote it through staging to production unchanged.
Netbay Developer Relations
Netbay Engineering
On this page
A surprising number of deployment pipelines rebuild the application on every target: CI builds once, then the staging server runs another build, then production runs yet another. If any step produces different output — a non-deterministic dependency resolution, a differing base image, a changed timestamp — you are testing and shipping different software without realizing it. Immutable artifacts fix this: build exactly once, and promote that single, versioned build from stage to stage without touching it.
What immutable means in practice
An immutable artifact has three properties:
- Built once, producing a byte-identical output that is stored and referenced by version.
- Never modified after creation; any change produces a new artifact with a new version.
- Referenced only by that version (a tag or digest), so you can always inspect exactly what is running.
For containerized apps, a container image with a deterministic content digest is the ideal vehicle. You push the image once, record its digest, and every environment — staging, canary, production — deploys from that exact digest. Re-tagging in place, or rebuilding at deploy time, breaks the contract.
# build once
docker build -t registry.example.com/web:$(git describe --tags) .
docker push registry.example.com/web:$(git describe --tags)
# record the digest for promotion
docker inspect --format='{{index .RepoDigests 0}}' registry.example.com/web:$(git describe --tags) > image.digestThe digest line you store is the source of truth for what runs next, letting every later environment reference the exact bytes that were tested.
The promotion agenda in CI
Promotion is the act of taking a tested artifact and deciding it is allowed in the next environment. Modeling this in CI keeps it explicit and auditable. A typical promotion flow runs the artifact through increasingly strict gates — unit tests, then integration, then a staging deploy, then production.
name: promote
on:
workflow_dispatch:
inputs:
environment:
description: promotion target
required: true
type: choice
options: [staging, production]
image:
description: artifact digest to promote
required: true
jobs:
promote:
runs-on: ubuntu-latest
steps:
- name: deploy pinned digest
run: |
docker pull app:latest
docker tag app:latest app:current
docker push app:currentEvery promotion references the same artifact from staging all the way to production, so the exact bytes tested in staging are the bytes released to users. (Pinning by digest in your real registry is even stricter than the tag shown here.)
Why rebuilding is a hidden risk
When each environment rebuilds, two problems appear. First, you cannot reproduce a bug in production by running the staged build, because they differ. Second, rollbacks become impossible with confidence — the old version may no longer build, or may build differently today. With immutable artifacts, rollback is trivial: point the environment back at a previously recorded digest that you know worked.
Versioning and metadata that help audit
Give artifacts rich, machine-readable identity. Embed the Git SHA, commit timestamp, and build number in the image labels so any running instance can tell you its provenance. This makes debugging substantially faster, because the running image declares what produced it.
FROM node:20-slim
ARG REVISION=dev
ARG CREATED=unknown
LABEL org.opencontainers.image.source="https://github.com/acme/web"
LABEL org.opencontainers.image.revision="$REVISION"
LABEL org.opencontainers.image.created="$CREATED"CI generates the revision and created timestamps as build arguments and passes them in, so provenance is baked into the image at build time rather than guessed.
Deterministic builds and the last mile
Truly immutable promotion assumes builds are reproducible enough that the artifact faithfully represents the source. Pin base images by digest, use lockfiles, and avoid pulling the latest tag at build time. The final mile is configuration: the immutable artifact should still be deployed with environment-specific config injected at runtime, so the artifact itself remains unchanged while its settings differ by stage.
Takeaway: build once, capture the digest, and promote that identical artifact through every environment. You get tested-and-shipped sameness, instant rollback, and clean audits. Running that pipeline against a Netbay VPS in Lucknow DC01, with a new instance in under 60 seconds, keeps your promotions fast and trustworthy — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance