Skip to content
Commitpedia
Log in Join & edit

Back up and restore a Docker named volume to a tar archive

A bash script that copies the contents of a named Docker volume into a .tar.gz on the host, and restores an archive into a volume, using a throwaway Alpine container.

Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?

Edit history of Back up and restore a Docker named volume to a tar archive: 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

What this changes

In backup mode it reads the volume (mounted read-only) and writes one .tar.gz file to the host. In restore mode it creates the target volume if missing and extracts the archive into it, overwriting files with the same names.

How to undo it

A backup can be undone by deleting the archive file. A restore writes into the volume; files that already existed under other names remain. To return to the state before a restore, restore the previous archive or remove the volume with docker volume rm.

Named volumes live inside Docker’s data directory, and on macOS and Windows that directory is inside a virtual machine, so you cannot just copy it. The portable way to back up a volume is to start a small container that mounts the volume and a host directory, and run tar inside it. This script wraps that pattern for both directions.

The script

Save it as volume-backup.sh and make it executable with chmod +x volume-backup.sh. Stop the container that uses the volume first, so the files are consistent; for databases prefer the database’s own dump tool and use this script for things like uploaded files.

#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage:
  $(basename "$0") backup  <volume> <archive.tar.gz>
  $(basename "$0") restore <archive.tar.gz> <volume>
USAGE
}

if [[ $# -ne 3 ]]; then
  usage >&2
  exit 2
fi

mode=$1

case "$mode" in
  backup)
    volume=$2
    archive=$3
    docker volume inspect "$volume" >/dev/null
    out_dir=$(cd "$(dirname "$archive")" && pwd)
    docker run --rm \
      -v "$volume":/from:ro \
      -v "$out_dir":/to \
      alpine:3 tar -czf "/to/$(basename "$archive")" -C /from .
    echo "backup written to $archive"
    ls -lh "$archive"
    ;;
  restore)
    archive=$2
    volume=$3
    if [[ ! -f "$archive" ]]; then
      echo "no such file: $archive" >&2
      exit 1
    fi
    in_dir=$(cd "$(dirname "$archive")" && pwd)
    docker volume create "$volume" >/dev/null
    docker run --rm \
      -v "$volume":/to \
      -v "$in_dir":/from:ro \
      alpine:3 tar -xzf "/from/$(basename "$archive")" -C /to
    echo "restored $archive into volume $volume"
    ;;
  *)
    usage >&2
    exit 2
    ;;
esac

How to use it

docker stop web
./volume-backup.sh backup uploads ./uploads-2026-10-15.tar.gz
docker start web

./volume-backup.sh restore ./uploads-2026-10-15.tar.gz uploads-copy
docker run --rm -v uploads-copy:/data alpine:3 ls -la /data

The last line lists the restored volume so you can confirm the contents before pointing a real container at it. Restoring into a new volume name, as above, is the safe way to check an archive without touching the original.

What the script does

  • docker volume inspect fails fast if the volume name is misspelled, instead of silently creating an empty one.
  • The host directory is resolved to an absolute path, because -v bind mounts need one.
  • :ro mounts the source read-only in backup mode, so a typo in the tar command cannot damage the volume.
  • alpine:3 is a few megabytes and includes tar with gzip support. --rm removes the helper container as soon as it finishes.
  • tar -C /from . archives the contents of the volume rather than the /from directory itself, so it restores to the root of the target volume.

Careful: in restore mode, files in the archive overwrite files with the same path in the target volume. Files that only exist in the volume are kept, so restoring onto a volume that already has data gives you a merge, not an exact copy.

Official documentation

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

  • 0055 Docker basics: images, containers and the commands you need An image is a read-only package of an app and its dependencies, and a container is a running instance of it. Learn… Beginner · Explains an idea · Linux, macOS, Windows Article Docker basics 15 Oct 2026
  • 0056 Docker Compose: run a small web app with a database Docker Compose describes several containers, their ports, volumes and environment in one compose.yaml file, then starts them all with docker compose up. Intermediate · Step by step · Linux, macOS, Windows Article Docker basics · Docker Compose 15 Oct 2026
  • 0250 Containerize a Node.js app and run it with PostgreSQL using Docker Compose Package a small Node.js web app in a multi-stage Docker image, then run it next to PostgreSQL with Docker Compose, named volumes,… Intermediate · Guided project · Linux, macOS, Windows Article Docker basics · Docker Compose · PostgreSQL 15 Oct 2026
  • 0268 What is a container? A container is a lightweight box that packs a program with everything it needs so it runs the same on any computer. Beginner · Explains an idea · Any system Article Docker basics 15 Oct 2026
  • 0327 Docker images, containers and volumes explained An image is a read-only template, a container is a running copy of it with a thin writable layer, and a volume… Beginner · Explains an idea · Linux, macOS, Windows Article Docker basics 15 Oct 2026
  • 0328 Install Docker Engine on Ubuntu and Debian Set up Docker's official apt repository, install Docker Engine with the Compose and Buildx plugins, run hello-world and let your user run… Beginner · Step by step · Linux Article Docker basics · Packages & updates 15 Oct 2026

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +3,385 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?