docker tag

docker tag adds a new name to an image that already exists in your local Docker image store. It matters because registries, teams, CI systems, and deployments all identify images by repository names and tags, not by vague descriptions like the image I just built. Retagging is how you turn a local image such as web-demo:1.0 into a registry-ready reference such as registry.example.com/team/web-demo:1.0.

Overview: How docker tag Works

A Docker image is read-only content: a configuration object plus a stack of filesystem layers. The local Docker image store can keep several references that all point to the same image ID. A reference includes a repository name and usually a tag, such as web-demo:1.0. When you run docker tag, Docker does not rebuild the image, copy layers, or contact a registry. It simply records another local reference to the same image content.

This is easier to understand if you separate image content from image names. The content is identified internally by digests and image IDs. The name is a human and registry-facing label. If web-demo:1.0 and registry.example.com/team/web-demo:1.0 show the same image ID in docker image ls, they are two names for one local image, not two independent images.

Image references have a structured form: [registry-host[:port]/][namespace/]repository[:tag]. The short reference nginx:1.27-alpine uses Docker Hub by default. A private registry reference includes a host name, such as registry.example.com/team/api:2.3.0. The tag is the part after the final colon. If you omit the tag, Docker assumes latest, which is only an ordinary tag name. It does not mean newest or safest.

docker tag is commonly used after a build. You might build a local image as payments-api:2026.08.03, test it, then add registry.example.com/platform/payments-api:2026.08.03 so it can be pushed. The push step is separate. docker push uploads missing layer blobs, uploads a manifest, and sets the remote tag in the registry. Until you push, the new tag exists only on your machine.

Tags are mutable unless your registry or release process prevents movement. Locally, retagging an existing target name points that target at different image content. Remotely, pushing a tag that already exists can move the registry tag. This is useful for moving channel names like staging or stable, but release tags such as 1.4.2 should usually be treated as immutable.

Syntax

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
Part Meaning
SOURCE_IMAGE[:TAG] The existing local image reference. You may also use an image ID instead of a name.
TARGET_IMAGE[:TAG] The new local image reference to create. Include the registry host and namespace when preparing to push.
:TAG The image tag. If omitted, Docker uses :latest.
registry-host The registry location, such as registry.example.com, ghcr.io, or localhost:5000.
namespace An account, organization, or project path used by the registry.

There are no important behavioral flags for docker tag. The command is intentionally small: source reference in, target reference out. The related command docker image tag is an alias with the same behavior.

Examples

Example 1: Add a Version Tag to a Local Image

docker pull alpine:3.20
docker tag alpine:3.20 tiny-base:3.20
docker image ls tiny-base

Output:

3.20: Pulling from library/alpine
Digest: sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1
Status: Downloaded newer image for alpine:3.20
docker.io/library/alpine:3.20
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
tiny-base    3.20      324bc02ae123   4 weeks ago    7.8MB

Docker pulled alpine:3.20, then added tiny-base:3.20 as another local reference. The underlying layers were not copied. If you also list alpine:3.20, it will have the same image ID as tiny-base:3.20.

Example 2: Build Once, Then Tag for a Registry

FROM nginx:1.27-alpine
COPY index.html /usr/share/nginx/html/index.html
docker build -t web-demo:1.0 .
docker tag web-demo:1.0 registry.example.com/team/web-demo:1.0
docker image ls registry.example.com/team/web-demo

Output:

[+] Building 1.6s (7/7) FINISHED
 => exporting to image
 => naming to docker.io/library/web-demo:1.0
REPOSITORY                           TAG       IMAGE ID       CREATED          SIZE
registry.example.com/team/web-demo   1.0       9b1f2c3d4e5f   12 seconds ago   48.3MB

The Dockerfile uses a pinned base tag, nginx:1.27-alpine, instead of nginx or latest. The build creates the local image web-demo:1.0. The tag command then adds the registry-qualified name that docker push would use. Nothing has been uploaded yet.

Example 3: Create Release and Channel Tags

docker tag web-demo:1.0 registry.example.com/team/web-demo:2026.08.03
docker tag web-demo:1.0 registry.example.com/team/web-demo:stable
docker image ls registry.example.com/team/web-demo

Output:

REPOSITORY                           TAG          IMAGE ID       CREATED         SIZE
registry.example.com/team/web-demo   1.0          9b1f2c3d4e5f   2 minutes ago   48.3MB
registry.example.com/team/web-demo   2026.08.03   9b1f2c3d4e5f   2 minutes ago   48.3MB
registry.example.com/team/web-demo   stable       9b1f2c3d4e5f   2 minutes ago   48.3MB

This pattern gives the same tested image multiple useful names. 2026.08.03 is an immutable release-style tag. stable is a moving channel tag that can later point to a newer tested image. Docker does not enforce those meanings; your team and registry policies do.

Example 4: Tag and Push to a Local Registry

docker run -d -p 5000:5000 --name local-registry registry:2
docker tag web-demo:1.0 localhost:5000/web-demo:1.0
docker push localhost:5000/web-demo:1.0

Output:

The push refers to repository [localhost:5000/web-demo]
5f70bf18a086: Pushed
d4fc045c9e3a: Pushed
1.0: digest: sha256:30f2f3d7a51b4a1f58fb38dfc6b26b04caa6c7d50a9fb8a4d7a4d01fd7f4b8b2 size: 856

Here the first command starts a registry container on your machine. The tag adds a name whose registry host is localhost:5000. The push uploads the image content and creates the remote 1.0 tag in that registry. docker tag prepared the name; docker push performed the distribution.

How It Works Step by Step

  1. The Docker CLI sends the source and target image references to the Docker daemon.
  2. The daemon resolves the source reference in the local image store. If the source tag is omitted, it looks for latest.
  3. Docker verifies that the source image exists locally. docker tag does not automatically pull missing source images.
  4. The daemon parses the target reference into registry host, namespace, repository, and tag components.
  5. Docker records the target reference as another name for the same image ID and layer chain.
  6. If the target reference already existed locally, it now points at the new source image.
  7. No image layers are copied, compressed, rebuilt, or uploaded during the tag operation.
  8. Later, docker push TARGET_IMAGE:TAG contacts the target registry, uploads missing blobs, uploads a manifest, and sets the remote tag.

When a container is eventually started from the tagged image, Docker still uses the same mechanics as any other image: it mounts the read-only image layers, adds a thin writable container layer, and starts the configured process. The tag chosen at run time only selects which image content to use.

Common Mistakes

Expecting docker tag to Push

docker tag web-demo:1.0 registry.example.com/team/web-demo:1.0

This creates a local name only. A teammate or server cannot pull that tag from the registry until you push it:

docker push registry.example.com/team/web-demo:1.0

Forgetting the Registry Host

docker tag web-demo:1.0 team/web-demo:1.0

This does not name registry.example.com. Without an explicit host, Docker treats it as a Docker Hub-style name. Use the complete registry-qualified reference when preparing for a private registry:

docker tag web-demo:1.0 registry.example.com/team/web-demo:1.0

Accidentally Creating latest

docker tag web-demo:1.0 registry.example.com/team/web-demo

Because no target tag was written, Docker creates registry.example.com/team/web-demo:latest. That may be acceptable for a development convenience tag, but it is a poor production release identifier. Write the target tag explicitly:

docker tag web-demo:1.0 registry.example.com/team/web-demo:1.0

Treating a Retag as a Backup

docker tag web-demo:1.0 web-demo:backup

This is only another local reference to the same image content. It is not an independent archive. If the host is lost, the tag is lost too. Durable storage comes from pushing to a registry and keeping the source, Dockerfile, build inputs, and release metadata.

Best Practices

  • Use explicit target tags. Avoid relying on implicit latest.
  • Include the registry host when preparing an image for a private registry, for example registry.example.com/team/app:1.0.0.
  • Treat release tags as immutable. Publish 1.0.1 instead of moving 1.0.0 to changed content.
  • Use channel tags such as stable, staging, or dev only when a moving pointer is intentional.
  • Build with a specific tag, retag the exact tested image, then push the registry-qualified tag.
  • Record the digest printed by docker push for audits and reproducible deployments.
  • Use pinned base image tags in Dockerfiles, such as nginx:1.27-alpine, and rebuild regularly for updates.
  • Do not bake secrets into images before tagging or pushing them. Image layers and metadata can persist even after later changes.
  • Clean up unwanted local references with docker image rm name:tag, understanding that image content remains if another tag or container still references it.

Practice Exercises

  1. Pull alpine:3.20, tag it as lab-alpine:3.20, and list both references. Expected end state: both names point to the same image ID.
  2. Build a small static Nginx image named site-demo:0.1.0, then add a registry-qualified tag for localhost:5000/site-demo:0.1.0. Hint: tagging does not require the registry to be running.
  3. Design a tagging scheme for a service that has development, staging, and production environments. Include one immutable release tag and one moving channel tag, and decide which one your deployment scripts should use.

Summary

  • docker tag creates a new local image reference for existing image content.
  • It does not rebuild layers, copy image data, pull missing images, or push to a registry.
  • Registry-ready names include a registry host, namespace, repository, and explicit tag.
  • Omitting a tag creates or uses latest, which is just an ordinary mutable tag name.
  • Use immutable release tags for reproducibility and moving channel tags only when intentional.
  • Distribution happens with docker push, which uploads missing blobs and sets the remote registry tag.