docker save and docker load
docker export worked by taking a container’s filesystem and turning it into an archive.
But what if you want to move the Docker image itself?
That’s where docker image save and docker image load come in.
The key idea is:
Docker Image
|
| docker image save
v
Image archive
|
| docker image load
v
Docker ImageNotice the starting point:
export → container
save → imageThat is the first thing to remember.
Start with an Image
Let’s use a small image:
docker image pull alpine:latestCheck it:
docker image lsYou should see something similar to:
REPOSITORY TAG IMAGE ID ...
alpine latest ...We now have an image that we want to move to another Docker host.
Save the Image
Run:
docker image save alpine:latest --output alpine.tarDocker creates:
alpine.tarConceptually:
alpine:latest
|
| docker image save
v
alpine.tarThis archive represents the Docker image, including the information Docker needs to restore that image.
That’s very different from the filesystem-only archive produced by docker container export.
What Does save Preserve?
The easiest mental model is:
docker image savepackages an image so Docker can restore the image later.
That means the image’s layers are preserved.
For example, imagine an image conceptually made from:
Layer 3 ← application files
↓
Layer 2 ← dependencies
↓
Layer 1 ← base filesystemSaving the image preserves that layered image structure in the archive.
Docker Image
|
+── Layer 3
+── Layer 2
+── Layer 1
+── image metadata
|
v
image.tarThis is why save is the appropriate choice when you want to move an actual Docker image between Docker hosts.
Load the Image
Now imagine alpine.tar has been copied to another machine.
On that machine, run:
docker image load --input alpine.tarDocker restores the image.
Check:
docker image lsYou should see:
alpine latestThe flow is:
Machine A
alpine:latest
|
| save
v
alpine.tar
|
| copy file
v
Machine B
alpine.tar
|
| load
v
alpine:latestThe image is now available on Machine B.
Run the Loaded Image
You can create a container from it:
docker container run --rm alpine:latest \
echo "Hello from the loaded image"You should get:
Hello from the loaded imageNotice what happened.
We didn’t recreate the image from its Dockerfile.
We didn’t pull it from a registry.
We restored the image from the archive.
Image archive
|
| load
v
Docker image
|
| run
v
ContainerSave Multiple Images
One useful feature of docker image save is that you can save multiple images into the same archive.
For example:
docker pull alpine:latest
docker pull busybox:latestThen:
docker image save \
alpine:latest \
busybox:latest \
--output base-images.tarNow:
base-images.tar
|
+── alpine:latest
|
└── busybox:latestOn another machine:
docker image load --input base-images.tarBoth images are loaded.
This is useful when several related images need to be transferred together.
Tags Are Preserved
Suppose you have:
my-app:1.0
my-app:2.0and save them:
docker image save \
my-app:1.0 \
my-app:2.0 \
--output my-apps.tarAfter loading:
docker image load --input my-apps.tarthe image tags are restored too.
That is another important difference from the filesystem-oriented export workflow.
You’re moving Docker images, not just a collection of files.
Image Layers Can Be Shared
Images often share layers.
For example:
app:1.0 ──┐
├── shared base layer
app:2.0 ──┘When you save multiple images together, Docker can represent shared layers without treating them as completely unrelated copies.
Conceptually:
+── app:1.0
|
shared layer +
|
+── app:2.0The archive therefore represents the image set and the layers needed to reconstruct it.
You don’t need to manually identify or copy individual layers.
Docker handles that.
--output and --output’s Short Form
The explicit form we’ve used is:
docker image save alpine:latest --output alpine.tarYou may also see:
docker image save alpine:latest -o alpine.tar-o is the short form of --output.
Both mean:
"Write the image archive to this file."The longer form is often easier to read.
Load Options
The corresponding option is:
--inputFor example:
docker image load --input alpine.tarYou may also see the shorter:
docker image load -i alpine.tarAgain, they express the same idea:
load this archive
↓
restore these Docker imagesYou Can Load from Standard Input
Just as an archive can be written to standard output, an image can also be loaded from standard input.
For example:
docker image save alpine:latest | docker image loadThis transfers the image directly between the two Docker commands without creating a named archive file.
Conceptually:
docker image save
|
| stdout
v
docker image loadThis is useful for piping image data between processes.
For normal learning and manual transfer, though, the file-based version is easier to see:
save → alpine.tar → loadSave and Load Do Not Need a Registry
This is one of the reasons these commands are useful.
You can do:
Machine A
|
| docker image save
v
image.tar
|
| USB / file transfer / shared storage
v
Machine B
|
| docker image load
v
Docker imageThere is no registry involved.
This makes save/load useful for:
- offline machines
- air-gapped environments
- manual image transfer
- backups of image artifacts
- moving images between Docker hosts without pushing them to a registry
A registry becomes useful when you want a central place from which multiple machines can pull the image.
We’ll get there later.
Save/Load vs Building Again
Suppose Machine A has:
my-app:1.0You could theoretically recreate the image on Machine B from the same Dockerfile and build context.
But that is not always the same thing as transferring the exact image you already have.
With:
docker image save my-app:1.0 --output my-app.taryou’re taking the existing image and packaging it for transfer.
Then:
docker image load --input my-app.tarrestores that image on the destination.
So the workflow is:
Existing image
|
| save
v
Archive
|
| transfer
v
load
|
v
Same image available on another Docker hostSave/Load Is Different from Export/Import
You now have two archive workflows:
EXPORT / IMPORT
Container
|
| export
v
Filesystem archive
|
| import
v
Imageand:
SAVE / LOAD
Image
|
| save
v
Image archive
|
| load
v
ImageThis difference is the central idea of this lesson.
Don’t think:
export = save
import = loadThink:
export/import
→ container filesystem
save/load
→ Docker imageWe’ll compare all four commands directly in the next lesson.
A More Concrete Example
Imagine you built an application image:
my-store:1.0Your production server is isolated from the internet.
You could do this on your development machine:
docker image save \
my-store:1.0 \
--output my-store.tarTransfer:
my-store.tarto the production server.
Then:
docker image load --input my-store.tarNow the production server has:
my-store:1.0You can create the container:
docker container run \
--name store \
my-store:1.0The important point is that the registry was unnecessary.
Development
|
| save
v
my-store.tar
|
| physical/file transfer
v
Production
|
| load
v
my-store:1.0What You Should Remember
Keep this mental model:
IMAGE
|
| docker image save
v
IMAGE ARCHIVE
|
| docker image load
v
IMAGEAnd compare it with what you learned previously:
CONTAINER
|
| docker container export
v
FILESYSTEM ARCHIVE
|
| docker image import
v
IMAGEThe starting object tells you which pair you need.
Have a container filesystem?
→ export / import
Have a Docker image?
→ save / loadClean Up
Remove the archive:
rm alpine.tarIf you also created the multi-image archive:
rm base-images.tarOn Windows PowerShell:
Remove-Item alpine.tar
Remove-Item base-images.tarThe images themselves can remain if you want to use them later.
What’s Next
Now that you’ve seen both mechanisms separately, the next lesson will put them side by side.
We’ll answer the question that causes the most confusion:
Why does Docker have both
export/importandsave/loadif both can move something into a.tarfile?
That’s where the difference between a container filesystem and a Docker image becomes impossible to miss.