Skip to content
Latchkey

crane copy: Daemonless Registry-to-Registry Copy

crane copy transfers an image from one registry reference to another with no local daemon, preserving the full manifest by default.

crane, from go-containerregistry, is a single static binary that talks straight to registries. crane copy mirrors an image without pulling layers to disk.

What it does

crane copy reads the manifest and blobs of the source reference and writes them to the destination reference over the registry API. For a multi-arch index it copies every child manifest by default, keeping the same digest.

Common usage

Terminal
# copy one image reference
crane copy docker.io/library/nginx:1.25 ghcr.io/acme/nginx:1.25

# copy every tag of a repository
crane copy --all-tags docker.io/library/redis ghcr.io/acme/redis

# authenticate first (writes to docker config)
crane auth login ghcr.io -u "$GH_USER" -p "$GH_TOKEN"

Options

FlagWhat it does
SRC DSTSource and destination references (positional)
--all-tags, -aCopy all tags in the repository
--platform os/archCopy only the given platform from an index
--insecureAllow HTTP / skip TLS verification
--jobs NNumber of concurrent copy jobs

In CI

crane is a great mirror tool in constrained runners: one small binary, no daemon, authenticates with crane auth login (or a mounted docker config). Copy without --platform to keep the multi-arch index intact.

Common errors in CI

"UNAUTHORIZED: authentication required" means run crane auth login or provide a docker config. "MANIFEST_UNKNOWN: manifest unknown" means the source tag/digest does not exist. "NAME_UNKNOWN: repository name not known to registry" means the destination repo path is wrong or was never created. "unsupported MediaType" appears when copying between a registry that only accepts one schema; copy the specific --platform or convert first.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →