Skip to main content

Image Digest

A content-addressable SHA256 hash that uniquely and immutably identifies a specific version of a Docker image. Unlike tags which can be overwritten, a digest always refers to exactly the same image bytes.

Image Digest — The Immutable Identity of a Docker Image

What Is an Image Digest in Simple Terms?

A Docker image tag like nginx:1.25 is just a label that can be moved — someone can push a new image with the same tag tomorrow and nginx:1.25 will point to completely different bytes. A digest is a SHA256 hash of the exact image content — it is mathematically impossible for two different images to have the same digest.

Using a digest instead of a tag means you always get exactly the same image, no matter when or where you pull it.

◈ DIAGRAM
Tag (mutable):
nginx:1.25 -> points to image A today
nginx:1.25 -> could point to image B tomorrow (if re-tagged)
Digest (immutable):
nginx@sha256:a84f9c2b1d3e... -> ALWAYS points to image A
Forever. Cannot change. Guaranteed.

Working With Digests

Bash
# See digest for a local image
docker images --digests nginx:1.25
# REPOSITORY TAG DIGEST SIZE
# nginx 1.25 sha256:a84f9c2b1d3e... 187MB
# Get digest after pulling
docker pull nginx:1.25
docker inspect nginx:1.25 --format '{{index .RepoDigests 0}}'
# nginx@sha256:a84f9c2b1d3e...
# Pull by digest (guaranteed reproducible)
docker pull nginx@sha256:a84f9c2b1d3e...
# Pin by digest in Dockerfile (most reproducible builds)
FROM nginx@sha256:a84f9c2b1d3e...
# This Dockerfile ALWAYS uses exactly the same base image
# Pin with tag AND digest (readable + safe)
FROM nginx:1.25@sha256:a84f9c2b1d3e...

Why Digests Matter in Production

TEXT
Scenario at Zerodha:
Trading system Dockerfile: FROM node:20-alpine
Monday: node:20-alpine = node 20.10.0, 0 CVEs
Friday: security patch pushed, node:20-alpine updated
CI rebuilds: gets new image automatically (good)
But: unexpected change in behavior possible
With digest pinning:
FROM node:20-alpine@sha256:abc123...
Every build uses exact same image
Updates are explicit PRs that can be reviewed and tested
No surprise changes in production

Automated Digest Updates

YAML
# Renovate config to automate base image updates
# renovate.json
{
"extends": ["config:base"],
"docker": {
"enabled": true,
"pinDigests": true
}
}
# Renovate opens PRs automatically when base image digests change
# Your CI tests the new digest before merging
# You get: immutability + automatic updates + CI validation
Remember

Tags are aliases — they can be updated to point to different images. Digests are content hashes — they never change. For fully reproducible builds that cannot be silently broken by a registry push, always pin by digest. Use Renovate or Dependabot to automate digest updates so you get security patches without manual work.

Frequently Asked Questions

How is an image digest different from a tag like myapp:latest?

A tag is a mutable pointer — `myapp:latest` can point to a completely different set of image layers tomorrow than it does today, because tags are just labels someone can re-push. A digest (`myapp@sha256:abc123...`) is computed from the content of the image manifest itself, so it's cryptographically tied to one exact set of bytes; if even a single layer changes, the digest changes too. Pulling by digest guarantees you get precisely the image that was tested.

Where does pinning to image digests actually matter in a deployment pipeline?

Production Kubernetes deployments and any security-sensitive environment should reference images by digest, not tag — otherwise a `latest` or even a versioned tag like `v1.2.0` can be silently overwritten (accidentally or maliciously) and your cluster pulls different code without any manifest change. The tradeoff is readability: digests are illegible in a diff, so many teams pin CI to resolve a tag to its digest at build time and store that digest in the deployment manifest.