skip to content

In a Dockerfile's FROM instruction, what is the difference between referencing a base image by tag (for example ubuntu:24.04) and by digest (image@sha256:...), and when does each matter?

level: middleimportance: must knowfreq 60%

answer

  1. tag = mutable pointer, digest = immutable content hash
  2. latest is just a default tag name, not newest
  3. FROM img:tag@sha256:... keeps both readability and pinning
  4. pinned digest never gets CVE fixes -> automate bumps
  5. pin the index digest, not one platform's manifest

basics

~20 s

A tag is a mutable pointer: the same tag can resolve to different image content over time. A digest is the sha256 hash of the image manifest, so it is immutable and content-addressed. Tags give you automatic patch updates; digests give you reproducible, verifiable builds. Pin digests for release builds and update them with automation.

solid answer

~50 s

A tag is a mutable label in the registry. `ubuntu:24.04` is republished with security fixes, and even `:latest` is nothing but a default tag name. Two builds a month apart from the same Dockerfile can therefore produce different images. A digest reference like `ubuntu@sha256:abc...` addresses the manifest by its content hash, so it either resolves to exactly those bytes or fails. Digest pinning gives reproducibility and a supply-chain guarantee: nobody can swap content under a tag you already pinned. The cost is that you stop receiving upstream patches silently, so a pinned digest that nobody bumps is a stale, unpatched base. The practical setup is pin by digest, keep the human-readable tag in a comment or in the `FROM image:tag@sha256:...` combined form, and let Renovate or Dependabot open PRs bumping the digest. Note the layer cache is not the mechanism here: the builder still resolves the tag against the registry unless `--pull` behaviour or an explicit digest says otherwise.

code

dockerfile · 3 lines
dockerfile
FROM debian:bookworm-slim@sha256:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates \
 && rm -rf /var/lib/apt/lists/*

go deeper

for a junior

Know that tags can move and that :latest is not a version; a digest is an exact, unchanging reference.

for a middle

Explain the mechanics (manifest hash, combined tag@digest form) and the reproducibility versus auto-patching trade.

for a senior

Frame it as supply chain: digest pinning plus automated bumps plus scanning, and explain the multi-arch index nuance.

for a principal

Set the org policy: digests in release pipelines, a golden base catalogue, bump automation and rebuild SLAs, and the link to signing, provenance attestations and SBOMs.

## Tags are pointers, not versions In an OCI registry, a repository holds content-addressed blobs and manifests. A tag is a mutable name that points at one manifest digest. Pushing again with the same tag simply repoints it. This is not an abuse of the system; it is how distributions ship patches: ubuntu:24.04 is rebuilt regularly so that consumers pulling that tag get current security fixes. :latest carries no special meaning to the registry at all; it is merely the tag used when none is specified. The consequence is that FROM ubuntu:24.04 is not a reproducible instruction. The same Dockerfile, the same source tree, and the same build command can produce two different images on two different days, because the base moved. That is usually good (you inherit fixes) and occasionally terrible (a base change breaks your build or silently alters behaviour, and you cannot reconstruct the image that shipped last Tuesday). ## Digests are content addresses A digest reference is repository@sha256:<hex>, where the hex is the SHA-256 of the image manifest bytes. The manifest in turn lists the config blob and layer blobs by their own digests. Because the hash covers the manifest, and the manifest covers everything else, a digest uniquely and verifiably identifies exact image content. The client recomputes the hash on pull, so a registry cannot serve you different bytes under that digest without detection. Docker also supports the combined form FROM ubuntu:24.04@sha256:abc..., which is the best of both: the tag documents intent for a human reader, and the digest is what actually resolves. Multi-stage builds can also digest-pin each stage's base independently. ## Multi-arch nuance For multi-platform images the tag usually points at an image index (manifest list) that enumerates per-platform manifests. Pinning the index digest keeps multi-arch behaviour: the client still selects the right platform entry. Pinning a single platform-specific manifest digest instead locks the build to that one architecture, which is a common accident when people copy a digest out of a registry UI on an amd64 laptop and then break arm64 builds. ## Choosing a policy Use tags when you want an unattended stream of upstream patches and reproducibility does not matter much: local development, exploratory work, images rebuilt constantly anyway. Use digests when the build must be reproducible or auditable: release pipelines, regulated environments, anything where you sign images or produce an SBOM and must be able to say precisely what shipped. Digest pinning also removes a real supply-chain vector, where an attacker with push access moves a tag to malicious content and every downstream build inherits it on the next rebuild. The standard failure mode of digest pinning is staleness. A digest never gets a CVE fix; it is frozen by definition. So a pinning policy without an automated bump process trades a small risk (surprise upstream change) for a larger one (running a base image with known unpatched vulnerabilities for a year). Renovate and Dependabot both understand Dockerfile digest pins and will open pull requests that update the digest and the accompanying tag comment, which lets the change go through code review and CI like any other dependency bump. A related distinction worth stating in an interview: pinning affects resolution, not caching. The BuildKit cache may reuse layers, but the base reference is resolved against the registry; with a mutable tag, whether you pick up a new base depends on cache state and on whether the build pulls. That indeterminism is exactly what digest pinning removes.

  • If you pin every base image by digest, how do you avoid shipping images with known unpatched CVEs?
    Automate the bump. Renovate or Dependabot watch Dockerfile digest pins and raise pull requests when the upstream tag moves, so updating the base becomes a reviewed, CI-tested change rather than an invisible one. Pair that with scheduled rebuilds and image scanning so a base with new findings is surfaced even when the tag itself has not moved yet.
  • You pinned a digest and now arm64 builds fail with 'no match for platform'. What happened?
    You almost certainly pinned a platform-specific manifest digest instead of the multi-platform image index digest. The index enumerates per-platform manifests and lets the client pick; a single manifest pin hard-codes one architecture. Re-resolve the tag with docker buildx imagetools inspect and pin the index digest.
  • Does using :latest ever make sense?
    Rarely in a Dockerfile. It is just the default tag name, gives no version information, and makes rollbacks and incident forensics guesswork because you cannot tell what was running. It is acceptable for throwaway local experiments; for anything built by CI, use an explicit tag and ideally a digest.

A tag is like a bookmark labelled 'current edition' that the publisher can silently repoint to a reprint; a digest is like citing a specific printing by its exact checksum of every page.

saying these in an interview costs you the question

  • Believing :latest always means the newest published image
  • Assuming the same Dockerfile always produces the same image without digest pinning
  • Thinking a digest identifies a tag, rather than the exact manifest content
  • Pinning digests and never updating them, then calling the build secure
  • Copying a platform-specific digest and breaking multi-architecture builds

context