Image Tags, Digests, Mutable vs Immutable References, Pull Policies, Pinning, and Reproducibility: Concepts, Architecture, and Mental Model
Tags are convenient release names; digests are content identities. This lesson builds a precise model from repository and mutable tag through registry resolution, manifest or image-index digest, platform-specific content, local image identity, and the container that actually runs.
Learning objectives
- Explain why a repository tag is a mutable lookup name while a manifest or image-index digest is an immutable content identity.
- Distinguish registry digest, multi-platform index digest, platform-specific manifest digest, local image ID/config digest, and the image reference stored on a container.
-
Describe how
missing,always, andneverpull policies change registry lookups without changing the meaning of a digest pin. - Design a release evidence chain that preserves a human-friendly alias and the exact digest promoted through environments.
- Recognize why digest pinning improves reproducibility but still requires an intentional update process for vulnerability remediation.
1. The problem: the same tag can name different bytes tomorrow
A deployment file that says example/app:stable looks
precise, but stable is only a registry tag. A publisher
can move that tag from release A to release B without changing the
text in your deployment file. If one host already has A cached and
another host resolves the registry after the move, the two hosts can
run different content while both report the same human-friendly tag.
This is not a Docker bug. Mutable aliases are useful for channels
such as stable, 3.4, or
nightly. The engineering mistake is treating the alias
as immutable evidence. A reliable release process records the digest
resolved at the moment of promotion and carries that identity
forward with tests, scans, attestations, and deployment records.
2. Mental model: name → resolution → immutable object → platform content
flowchart TD
A[repository:tag\nhuman-friendly mutable name] --> B[registry tag resolution]
B --> C{single or multi-platform?}
C -->|multi-platform| D[OCI image index\nimmutable digest]
D --> E[platform manifest\nlinux/amd64 digest]
D --> F[platform manifest\nlinux/arm64 digest]
C -->|single-platform| E
E --> G[config digest + layer digests]
G --> H[local image object / image ID]
H --> I[container created from exact local image]
The top-level digest may identify an image index. That index can
point to several platform-specific manifest digests. A local image
ID commonly corresponds to the config object identity for the
selected local image. These values can all start with
sha256: and still identify different objects.
3. Identity vocabulary: do not collapse these fields
| Identity | What it identifies | Mutable? | Operational use |
|---|---|---|---|
| Repository |
Registry namespace/name, such as
registry.example/team/app.
|
The name is stable; its tags can move. | Human organization and access policy. |
| Tag |
A registry alias such as 1.4.2 or
stable.
|
Yes. | Discovery, channels, compatibility labels. |
| Index digest | A multi-platform OCI index/manifest list. | No for fixed content. | Immutable identity of the complete platform set. |
| Manifest digest | One platform-specific image manifest. | No for fixed content. | Exact platform image identity. |
| Image ID | Local image config identity shown by the Engine. | No for that config. | Local store/object correlation; not a substitute for registry identity. |
| RepoDigest |
A repository-qualified digest association such as
repo@sha256:….
|
The association records immutable content. | Audit/pull/run by exact registry identity. |
5. Digest identity and the multi-platform wrinkle
A digest is computed from the serialized content of the object it names. Changing that object changes its digest. For a multi-platform release, the tag commonly points to an image index. The index has one digest; its amd64 and arm64 child manifests have different digests. Therefore, an evidence record should state whether it captured the index digest, a platform manifest digest, or both.
Use registry-aware inspection when the distinction matters:
docker buildx imagetools inspect busybox:1.37.0
docker buildx imagetools inspect busybox:1.37.0 --format '{{.Name}}'
Do not copy a digest from one platform field and describe it as the identity of the entire multi-platform release unless the object being identified is actually the index.
6. Local image ID versus registry digest
The Engine can have a local image before it has ever been pushed, so
a local image ID exists without a repository digest. After a
successful pull or push, RepoDigests can associate
local content with repository-qualified immutable identities. Those
are different pieces of evidence.
docker image inspect busybox:1.37.0 \
--format 'ID={{.Id}} RepoDigests={{json .RepoDigests}}'
7. Pull policy changes lookup behavior, not digest immutability
For docker run, --pull=missing is the
default, --pull=always performs a registry pull before
container creation, and --pull=never forbids an
implicit pull. With a floating tag, this determines whether a cached
local resolution can be reused. With a digest reference, the
identity is already fixed; pulling may fetch missing content, but it
cannot silently substitute different content under the same digest.
docker run --rm --pull=missing busybox:1.37.0 true
docker run --rm --pull=always busybox:1.37.0 true
docker run --rm --pull=never busybox:1.37.0 true
Compose has a broader policy surface, including time-based checks. Treat the policy as a freshness/lookup rule, not as artifact identity.
8. Build once, promote the same digest
A release pipeline should bind source revision, build inputs, builder/toolchain, tests, scan/attestation results, and the resulting registry digest. Promotion then attaches an environment-facing alias or deployment reference to that already-tested digest. Rebuilding “the same version” for staging and production creates new bytes and breaks the evidence chain even if the tag text is unchanged.
app:3.8.0 or app:stable.
registry/team/app@sha256:…, including platform
detail when required.
Evidence that the alias/deployment now references the already-tested digest, not a rebuild.
9. Read-only inspection before changing anything
docker version
docker context show
docker image ls --digests
docker image inspect IMAGE --format \
'ID={{.Id}} RepoTags={{json .RepoTags}} RepoDigests={{json .RepoDigests}} OS={{.Os}} Arch={{.Architecture}}'
docker inspect CONTAINER --format \
'Container={{.Id}} LocalImageID={{.Image}} RequestedImage={{.Config.Image}}'
Capture these fields before pulling, retagging, recreating, or deleting anything during an incident. A later successful pull can erase the evidence that the host had stale content.
10. Common misconceptions
- “latest means newest.” It is only a conventional tag name.
- “A semantic version tag cannot move.” Registries generally allow it unless policy prevents it.
- “The image ID is the registry digest.” They identify different objects/contexts.
- “Pinned means automatically secure forever.” Pinning freezes bytes; you still need controlled updates when better base images or fixes appear.
- “Always pull means reproducible.” With a mutable tag, always-pull intentionally asks the registry for the tag’s current meaning.
Knowledge check
Can app:stable identify different bytes at two
different times?
Yes. A tag is a mutable registry alias unless registry policy prevents reassignment.
If a tag points to a multi-platform index, is the index digest necessarily the same as the linux/amd64 manifest digest?
No. The index and each child platform manifest are separate content-addressed objects with separate digests.
What does --pull=always prove when you run a
mutable tag?
It proves Docker performed a registry pull before container creation; it does not make the tag immutable.
Why keep both a semantic version tag and a digest?
The tag is usable by humans and policy, while the digest preserves the exact immutable artifact identity.
Does digest pinning eliminate the need to update vulnerable base images?
No. It makes changes explicit and auditable; remediation still requires selecting and validating a newer digest.
Official references and version notes
-
docker image ls— digest display, local image IDs, and digest-addressed pull/create/run examples. -
docker image inspect— low-level local image metadata, including platform-aware inspection on capable stores. -
docker run— current--pull=missing|always|neversemantics. -
Compose
pull_policy—always,never,missing,build,daily,weekly, andevery_<duration>. - Docker build best practices — pinning base images by digest, controlled updates, and auditability tradeoffs.
-
docker buildx imagetools inspect— registry-side manifest/index and platform inspection. - Image digests — manifest-list/index versus per-platform image digest distinctions.
- OCI Image Index Specification — immutable index descriptors and platform selection.
- OCI Image Manifest Specification — config and layer descriptors addressed by digest.
- Docker Engine 29 release notes — Engine 29.8.1 baseline used when authoring this chapter.
- Buildx releases and BuildKit releases — current build-tool release history.
Version-sensitive statements were rechecked against primary documentation on 2026-09-21. The authoring baseline is Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, and Dockerfile frontend 1.27.0, but every executable lab records the versions and context actually present. Registry tags, platform indexes, local image stores, and Compose behavior can evolve independently; prefer observed digests and current primary documentation over memorized output.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.