19.1.4 Push CLI Command
A focused guide to Push CLI Command, connecting core concepts with practical Docker and container operations.
The push CLI command uploads a locally tagged image to a registry, and its practical usage extends beyond a single, basic invocation into pushing multiple tags efficiently, pushing an entire manifest list for multi-architecture images, and understanding the upload-side layer reuse and authentication behavior that mirrors much of what governs pulling.
Basic usage and the required tag-to-registry mapping
A push always targets whichever full reference, including registry hostname, the local image was actually tagged with; pushing requires the image to already be tagged appropriately, since docker push has no separate mechanism for specifying a destination beyond the tag itself:
docker tag my-api:1.4.2 registry.example.com/myorg/my-api:1.4.2
docker push registry.example.com/myorg/my-api:1.4.2
Attempting to push a locally built image still only tagged with a bare, unqualified name fails or, depending on configuration, attempts to push to Docker Hub by default, since the registry hostname is determined entirely by what the tag itself specifies.
Pushing multiple tags for the same image
Each tag requires its own explicit push invocation; there is no single command that pushes every locally applied tag for a given image at once, though a short script can iterate through several tags efficiently:
docker push registry.example.com/myorg/my-api:1.4.2
docker push registry.example.com/myorg/my-api:latest
for tag in 1.4.2 latest; do
docker push registry.example.com/myorg/my-api:$tag
done
Because both tags reference the identical underlying image content, the second push generally completes quickly, benefiting from the same layer-already-exists optimization on the upload side that pulling benefits from on the download side.
Layer reuse during push
The registry itself checks whether it already has a given layer before accepting another upload of identical content, which means pushing a second tag, or a second image sharing layers with one already pushed, uploads only the genuinely new, distinct layers rather than redundantly re-uploading shared content:
3f29a8c1: Layer already exists
8a1f3c9b: Pushed
This mirrors the pull-side layer reuse behavior directly, both relying on the same underlying content-addressed identification that makes recognizing already-present content possible on either side of the transfer.
Pushing multi-architecture manifest lists
For a multi-platform image built with docker buildx build --platform=..., the --push flag on the build command itself is the typical way to push the resulting manifest list directly as part of the build, since a plain docker push against a multi-platform build's local result does not correctly assemble and push the full manifest list on its own:
docker buildx build --platform=linux/amd64,linux/arm64 -t my-api --push .
Attempting to build multi-platform locally without --push and then push separately afterward generally does not work as expected, since the local image store does not retain every platform variant simultaneously the way the build-and-push-together approach does.
Authentication requirements
Pushing requires authentication to the target registry exactly the same way pulling from a private registry does, through docker login beforehand, with the same credential storage and --password-stdin considerations covered in dedicated registry authentication content applying identically here:
docker login registry.example.com
docker push registry.example.com/myorg/my-api:1.4.2
denied: requested access to the resource is denied
This specific error indicates either missing authentication entirely or insufficient write permission on the target repository even with valid authentication present, which is worth distinguishing directly, since the fix differs between authenticating at all versus requesting broader write access on an already-authenticated account.
Verifying a push succeeded
Confirming a push genuinely completed and the registry now has the expected content, rather than assuming success purely from the command exiting without an obvious error, is worth doing directly for anything feeding into an automated deployment pipeline:
docker manifest inspect registry.example.com/myorg/my-api:1.4.2
A successful response here, reflecting the just-pushed content, confirms the push genuinely succeeded and the registry now has exactly what was intended, rather than relying solely on the push command's own exit status as the only signal of success.
Common mistakes
- Attempting to push an image still tagged with only a bare, unqualified name, rather than the fully qualified registry-prefixed tag the push command actually requires.
- Assuming a single command pushes every locally applied tag for an image at once, rather than recognizing each distinct tag requires its own explicit push.
- Building a multi-platform image locally and attempting to push it separately afterward, rather than using
--pushdirectly as part of the buildx build command itself. - Not distinguishing between a missing-authentication error and an insufficient-write-permission error, applying the wrong fix for whichever actually applies.
- Assuming a push succeeded purely because the command exited without an obvious error, rather than independently confirming the registry now has the expected content.
The push CLI command's practical usage benefits from the same layer reuse principle that accelerates pulling, requires a fully qualified, registry-prefixed tag to function correctly at all, and for multi-platform images specifically depends on the combined build-and-push workflow rather than a separate push step performed after a purely local multi-platform build.