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
# 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
| Flag | What it does |
|---|---|
| SRC DST | Source and destination references (positional) |
| --all-tags, -a | Copy all tags in the repository |
| --platform os/arch | Copy only the given platform from an index |
| --insecure | Allow HTTP / skip TLS verification |
| --jobs N | Number 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.