Tag Images So You Can Find Them Later
Build one image under several tags, release a new version and roll back to the old one. After this, you can name images so a rollback is one command.
Course content
Sign in to save your progress.
-
Dockerfiles That Don't Rot
-
.dockerignore and What Belongs in the Build Context
-
ENTRYPOINT, CMD and When to Override Them
-
-
-
Data That Outlives Containers
-
Bind Mounts vs Named Volumes: Which One When
-
Permissions, Ownership and Why the Container Can't Write
-
-
-
Networks Beyond Defaults
-
Bridge Networks, Aliases and DNS
-
Publish Ports Without Exposing Everything
-
-
-
Compose for Real Apps
-
Services, depends_on and Healthchecks
-
Environment Files, Secrets and What Not to Commit
-
-
-
Images Across Machines
-
Tag Images So You Can Find Them Later
-
Push and Pull From a Registry Without Surprises
-
-
- Final Check: Docker Intermediate
Skip ahead: If you already tag every image with a version, skip to "latest is only a name", then go on to the next lesson.
Without tags, an image is a long hash that nobody remembers. With careless tags, you cannot tell which version is running or how to go back to the one that worked. A tag is cheap, and the habit decides whether a rollback takes one command or an afternoon. This lesson builds one image several times and shows what each tag points at.
One image, several names
An image name has up to four parts: registry/namespace/repository:tag. Everything but the repository is optional. The tag after the colon is just a label on an image. One image can carry many labels, and docker tag adds another without copying anything.
Build a small image with the version in a file, and give it a version tag at every level of detail, plus latest, in one command.
shop 1.0.0
FROM alpine:3.24
ARG VERSION=unknown
LABEL org.opencontainers.image.version=$VERSION
COPY version.txt /version.txt
CMD ["cat", "/version.txt"]
Set-Location tag-demo
docker build -q --build-arg VERSION=1.0.0 -t shop-app:1.0.0 -t shop-app:1.0 -t shop-app:1 -t shop-app:latest . | Out-Null
docker image ls shop-app --format "table {{.Repository}}\t{{.Tag}}" | Sort-Object
"different images: " + @(docker image ls shop-app --format "{{.ID}}" | Sort-Object -Unique).Count
REPOSITORY TAG
shop-app 1
shop-app 1.0
shop-app 1.0.0
shop-app latest
different images: 1
Four tags, one image. The last line counts distinct image IDs, and it is 1. A tag is a pointer, so adding or moving one costs nothing.
Why four? Each answers a different question. 1.0.0 is exactly this build and never moves. 1.0 is "the newest 1.0 patch", and 1 is "the newest 1.x". latest is "whatever I tagged last". People who want fixes without surprises follow 1.0. People who want exact repeatability use 1.0.0.
Release a new version
Change the version and build again. This time the minor and major pointers move to the new image, and 1.0.0 stays where it was.
Set-Content version.txt "shop 1.1.0"
docker build -q --build-arg VERSION=1.1.0 -t shop-app:1.1.0 -t shop-app:1.1 -t shop-app:1 -t shop-app:latest . | Out-Null
foreach ($t in "1.0.0", "1.0", "1.1.0", "1.1", "1", "latest") { "{0,-7} -> {1}" -f $t, (docker run --rm "shop-app:$t") }
"different images: " + @(docker image ls shop-app --format "{{.ID}}" | Sort-Object -Unique).Count
1.0.0 -> shop 1.0.0
1.0 -> shop 1.0.0
1.1.0 -> shop 1.1.0
1.1 -> shop 1.1.0
1 -> shop 1.1.0
latest -> shop 1.1.0
different images: 2
There are two images now. 1, 1.1 and latest moved to the new one, and 1.0.0 and 1.0 stayed on the old one. Nothing was deleted. If version 1.1.0 turns out to be broken, docker run shop-app:1.0.0 is the rollback, and it works because the old tag was never reused.
⚠ Warning: Never build a second, different image under a tag that people already use, such as 1.0.0. A version tag that moves is not a version. If you fix something, release 1.0.1.
latest is only a name
latest has no special meaning to Docker. It is the tag you get when you write none: docker run shop-app means shop-app:latest. It is not "the newest" and not "the most stable". It points at whatever was last tagged latest, and that can be an old build if someone tagged an old image by hand. In my run, latest followed the new build only because I listed it in the command.
docker tag shop-app:1.0.0 shop-app:latest
docker run --rm shop-app
shop 1.0.0
I pointed latest at the old image on purpose, and docker run shop-app happily ran version 1.0.0. So never deploy latest. Deploy an exact tag, and write that tag into your Compose file.
Put the version inside the image too
A tag lives outside the image, and anyone can move it. A label lives inside. I built the image with the standard org.opencontainers.image.version label, and you can read it back or filter on it.
docker image inspect shop-app:1.1.0 --format "{{json .Config.Labels}}"
docker image ls --filter "label=org.opencontainers.image.version=1.0.0" --filter "reference=shop-app" --format "{{.Repository}}:{{.Tag}}" | Sort-Object
{"org.opencontainers.image.version":"1.1.0"}
shop-app:1.0
shop-app:1.0.0
shop-app:latest
The filter found three tags that point at the 1.0.0 image: 1.0.0, 1.0 and latest, which I moved there by hand a moment ago. The label travels with the image when you push and pull it, so a running container can always be traced back to a version.
Removing a tag is not removing an image
docker rmi shop-app:1.1
docker run --rm shop-app:1.1.0
Untagged: shop-app:1.1
shop 1.1.0
docker rmi on a tag that is not the last one only removes that label ("Untagged"). The image stays while any other tag points at it. Remove the last tag and the image goes, which is the moment you cannot roll back any more.
💡 Tip: Tag with the exact version from your build or CI, and add the short Git commit as another tag, such as 1.1.0 plus a1b2c3d. When something is wrong in production, the commit tag tells you which code it is.
If something broke in production right now, could you run the previous version with one command, and what tag would you type?
About
Build one image under several tags, release a new version and roll back to the old one. After this, you can name images so a rollback is one command.
- Duration
- 5 min
- Last update
- 08/01/2026
Comments (0)
Sign in to commentNo comments yet.