docker build -t reference

Last reviewed on 2026-08-27

Naming and tagging an image at build time: syntax rules, multiple tags, registry prefixes, and what :latest really means.

Syntax

docker build -t [REGISTRY[:PORT]/][NAMESPACE/]NAME[:TAG] PATH

-t is the short form of --tag. It gives the image a name so you can refer to it later. Everything except NAME is optional.

The -t flag on docker build answers the question "what do I call this thing?". A build without -t still succeeds and still produces a real image, but that image has no name: it shows up in docker images as <none>:<none> and the only way to run it is by its ID. That is why almost every build command you will see in the wild carries a -t.

# Named and tagged
docker build -t myapp:1.4.2 .

# Named, tag omitted — Docker fills in :latest
docker build -t myapp .

# No -t at all — a dangling image you must address by ID
docker build .

Anatomy of an image reference

A full image reference has up to four parts. Docker fills in defaults for the ones you leave out:

PartExampleDefault if omitted
Registry host (and port)ghcr.io, registry.example.com:5000Docker Hub (docker.io)
Namespace / useracmelibrary on Docker Hub — which is why ubuntu resolves to docker.io/library/ubuntu
Repository namemyappRequired. This is the minimum -t accepts.
Tag1.4.2latest

Docker decides whether the first segment is a registry host or a namespace by looking for a dot, a colon, or the literal string localhost. acme/myapp is the acme namespace on Docker Hub; acme.io/myapp is the myapp repository on the registry acme.io. This one rule causes a surprising amount of confusion when a company's namespace happens to look like a hostname.

Rules the name and tag must follow

Applying several tags in one build

Repeat -t as many times as you need. The image is built once and every tag points at the same image ID, so this costs nothing extra:

docker build \
  -t myapp:1.4.2 \
  -t myapp:1.4 \
  -t myapp:latest \
  -t ghcr.io/acme/myapp:1.4.2 \
  .

This is the standard release pattern: an immutable exact version, a moving minor-version alias, a moving latest, and a copy of the exact version under the registry you will push to. Note that -t only names the image locally — pushing is a separate step, and docker push pushes one reference at a time:

docker push ghcr.io/acme/myapp:1.4.2
docker push ghcr.io/acme/myapp:latest

What :latest actually means

latest is not a special "newest" pointer maintained by Docker. It is simply the tag Docker substitutes when you do not write one, in both docker build -t myapp . and docker run myapp. It points at whatever image was most recently tagged latest, which can easily be older than other tags in the same repository — for example if you build myapp:2.0 without also tagging it latest.

Two practical consequences:

Retagging an image you already built

If you forgot a tag, you do not need to rebuild. docker tag adds another name to an existing image ID:

# Add a registry-qualified name to an image already built as myapp:1.4.2
docker tag myapp:1.4.2 ghcr.io/acme/myapp:1.4.2

# Rename a dangling image you built without -t
docker build . -q            # prints sha256:abc123…
docker tag sha256:abc123 myapp:1.4.2

Removing a tag with docker rmi myapp:1.4 deletes only that name. The image itself survives as long as at least one tag or container still references it.

Tagging in CI

The two values worth tagging with are the commit SHA (unique, immutable, always available) and the release version (human-readable, only meaningful on tagged commits):

SHA=$(git rev-parse --short HEAD)

docker build \
  -t "ghcr.io/acme/myapp:sha-${SHA}" \
  -t "ghcr.io/acme/myapp:latest" \
  --build-arg "VERSION=${SHA}" \
  .

Passing the same value in as a --build-arg lets the application report its own version, but be aware it changes the cache key of every instruction after the ARG is referenced — so reference it as late in the Dockerfile as possible.

Tagging multi-platform builds

With docker buildx, a single -t can name a manifest list covering several architectures. The tag then resolves per-platform at pull time:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t ghcr.io/acme/myapp:1.4.2 \
  --push .

Note the --push: a multi-platform result cannot be loaded into the local image store, so it goes straight to the registry. See the multi-architecture builds tutorial for the full workflow.

Common errors

MessageCause
invalid reference format: repository name must be lowercaseAn uppercase letter in the repository name — often a project name or a $USER variable interpolated straight into -t.
invalid reference formatA slash or colon inside the tag (a raw Git branch name), a trailing separator, or an empty tag after the colon.
"docker build" requires exactly 1 argumentThe context path is missing. -t consumes the value after it, so docker build -t myapp leaves nothing for the path — you need the trailing ..
denied: requested access to the resource is denied on pushThe tag's registry or namespace does not match the account you are logged in to. Retag with docker tag rather than rebuilding.

Related