The target host has no route to a registry, but it has a USB stick, and docker image save turns an image into a file you can carry. This guide produces a tar archive you can copy to another Docker host and load again with docker image load. Allow about ten minutes. The examples use Docker 29.8.1 from the installed docker-ce-cli package, version 5:29.8.1-1~ubuntu.24.04~noble.
Read the local command help before building a backup script. This is a read-only check:
$ docker --version
Docker version 29.8.1, build 4a63305
$ docker image save --help
Usage: docker image save [OPTIONS] IMAGE [IMAGE...]
Options:
-o, --output string Write to a file, instead of STDOUT
--platform strings Save only the given platform(s). Formatted as
os[/arch[/variant]]
The command accepts one or more image references. Its short alias is docker save, but docker image save makes the operation clearer in scripts and documentation.
Checkpoint: Confirm that the client can see the images you intend to export:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest ... ... ...
The rows and image IDs are host-specific. Record the exact repository and tag, not just an image ID copied from an old terminal window.
Use --output when the archive should have a named destination. This example writes the local alpine:latest tag:
$ docker image save --output alpine-latest.tar alpine:latest
The file is a Docker image archive. The command prints no progress on success, so check that the file exists and has a plausible non-zero size:
$ ls -lh alpine-latest.tar
-rw------- 1 you you 3.8M ... alpine-latest.tar
Your size will differ. Saving an image can need enough free space for all of its layers, metadata and tags. Check the destination filesystem before exporting a large production image.
Safety warning: --output writes the named file. Choose a new path or confirm that overwriting an existing archive is acceptable. An archive is a backup only after you have tested that it can be loaded.
A tar listing is a quick integrity and contents check. It does not execute anything in the image:
$ tar -tf alpine-latest.tar | sed -n '1,18p'
blobs/
blobs/sha256/
blobs/sha256/...
index.json
manifest.json
oci-layout
The digest filenames vary. Seeing image metadata and layer blobs is expected. To inspect the archive without unpacking it into the current directory, keep using tar -tf.
Warning: Do not extract an untrusted archive into a directory containing application files.
For a compressed transfer, put compression after the save stream:
$ docker image save alpine:latest | gzip > alpine-latest.tar.gz
$ ls -lh alpine-latest.tar.gz
Do not redirect ordinary Docker status or error output into the archive. Docker's image stream goes to standard output in this form, while diagnostics go to standard error. You can decompress the compressed file before loading, or stream it directly to docker image load on a compatible host.
Passing multiple image references creates one archive containing each requested image and its parent layers:
$ docker image save --output release-images.tar \
alpine:latest \
postgres:16-alpine
Tags matter here. alpine normally resolves to the latest tag, but an explicit tag makes the saved set easier to review and reproduce. If you need two versions from the same repository, list both:
$ docker image save -o alpine-two-tags.tar \
alpine:latest alpine:3
Tip: Before copying the archive, write down the references and the source host's image IDs. A tag can be moved later, while the archive keeps the image content selected at save time.
Docker 29.8.1 supports a comma-separated --platform list in the form os/arch/variant, such as linux/amd64,linux/arm64/v8. Without this option, Docker saves all platform variants present in the local image store for the requested image:
$ docker image save --platform=linux/amd64 \
--output alpine-amd64.tar alpine:latest
Use this when the receiving host or your transfer budget calls for one variant. The platform must already be available locally, because the command does not fetch a missing variant. If it is absent, Docker returns an error such as:
$ docker image save --platform=linux/s390x \
--output alpine-s390x.tar alpine:latest
Error response from daemon: no suitable export target found for platform linux/s390x
A successful archive is not proof that it suits every host. Match the saved platform to the destination architecture, or deliberately save the variants the destination needs.
A missing tag is an error, not an instruction to pull an arbitrary replacement:
$ docker image save -o missing.tar definitely-not-present:latest
Error response from daemon: No such image: definitely-not-present:latest
$ printf 'exit status: %s\n' "$?"
exit status: 1
Check the spelling with docker image ls, then decide whether the exact image should be pulled. Pulling changes local state and can introduce a different digest, so verify the image reference and digest before saving it. An elevated command is not a repair for a missing image.
If an export is interrupted, treat the partial file as unusable. Remove it only after confirming the exact path, then run the save again to a fresh destination:
$ test -f alpine-latest.tar && tar -tf alpine-latest.tar > /dev/null
$ echo "archive listing succeeded: $?"
archive listing succeeded: 0
Recovery: If the listing fails, move the partial file aside for investigation or delete that specifically named file. There is no Docker rollback operation because saving does not alter the image store.
Copy the archive using your normal controlled transfer process. Loading changes the destination host's local image store, so plan storage and access accordingly. On that host:
$ docker image load --input alpine-latest.tar
Loaded image: alpine:latest
$ docker image inspect alpine:latest --format '{{.Id}}'
sha256:...
The exact load message and image ID depend on the archive. Compare the destination ID or digest with the source record, then run the image's intended smoke test. Loading an archive does not start a container, change a service, or update a registry.
tar -tf.