Skip to content

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 Image

Notice the starting point:

export → container
save   → image

That is the first thing to remember.

Start with an Image

Let’s use a small image:

docker image pull alpine:latest

Check it:

docker image ls

You 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.tar

Docker creates:

alpine.tar

Conceptually:

alpine:latest
      |
      | docker image save
      v
  alpine.tar

This 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 save packages 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 filesystem

Saving the image preserves that layered image structure in the archive.

Docker Image
   |
   +── Layer 3
   +── Layer 2
   +── Layer 1
   +── image metadata
   |
   v
image.tar

This 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.tar

Docker restores the image.

Check:

docker image ls

You should see:

alpine       latest

The flow is:

Machine A

alpine:latest
      |
      | save
      v
 alpine.tar
      |
      | copy file
      v

Machine B

 alpine.tar
      |
      | load
      v
alpine:latest

The 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 image

Notice 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
Container

Save 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:latest

Then:

docker image save \
  alpine:latest \
  busybox:latest \
  --output base-images.tar

Now:

base-images.tar
    |
    +── alpine:latest
    |
    └── busybox:latest

On another machine:

docker image load --input base-images.tar

Both 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.0

and save them:

docker image save \
  my-app:1.0 \
  my-app:2.0 \
  --output my-apps.tar

After loading:

docker image load --input my-apps.tar

the 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.0

The 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.tar

You 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:

--input

For example:

docker image load --input alpine.tar

You may also see the shorter:

docker image load -i alpine.tar

Again, they express the same idea:

load this archive
       ↓
restore these Docker images

You 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 load

This transfers the image directly between the two Docker commands without creating a named archive file.

Conceptually:

docker image save
       |
       | stdout
       v
docker image load

This 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 → load

Save 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 image

There 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.0

You 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.tar

you’re taking the existing image and packaging it for transfer.

Then:

docker image load --input my-app.tar

restores that image on the destination.

So the workflow is:

Existing image
      |
      | save
      v
Archive
      |
      | transfer
      v
load
      |
      v
Same image available on another Docker host

Save/Load Is Different from Export/Import

You now have two archive workflows:

EXPORT / IMPORT

Container
    |
    | export
    v
Filesystem archive
    |
    | import
    v
Image

and:

SAVE / LOAD

Image
    |
    | save
    v
Image archive
    |
    | load
    v
Image

This difference is the central idea of this lesson.

Don’t think:

export = save
import = load

Think:

export/import
    → container filesystem

save/load
    → Docker image

We’ll compare all four commands directly in the next lesson.

A More Concrete Example

Imagine you built an application image:

my-store:1.0

Your 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.tar

Transfer:

my-store.tar

to the production server.

Then:

docker image load --input my-store.tar

Now the production server has:

my-store:1.0

You can create the container:

docker container run \
  --name store \
  my-store:1.0

The important point is that the registry was unnecessary.

Development
    |
    | save
    v
my-store.tar
    |
    | physical/file transfer
    v
Production
    |
    | load
    v
my-store:1.0

What You Should Remember

Keep this mental model:

IMAGE
  |
  | docker image save
  v
IMAGE ARCHIVE
  |
  | docker image load
  v
IMAGE

And compare it with what you learned previously:

CONTAINER
  |
  | docker container export
  v
FILESYSTEM ARCHIVE
  |
  | docker image import
  v
IMAGE

The starting object tells you which pair you need.

Have a container filesystem?
    → export / import

Have a Docker image?
    → save / load

Clean Up

Remove the archive:

rm alpine.tar

If you also created the multi-image archive:

rm base-images.tar

On Windows PowerShell:

Remove-Item alpine.tar
Remove-Item base-images.tar

The 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/import and save/load if both can move something into a .tar file?

That’s where the difference between a container filesystem and a Docker image becomes impossible to miss.

Last updated on