← Blog
A cream paper sleeve lifted above a dark green block with a coral stripe on a lavender surface.
Published on
2026-10-30

Docker volumes: persist container data and plan backups

Docker volumes keep application files outside a container's writable layer. A named volume can remain after the container is removed, so a replacement container can use the same data. That persistence does not make the volume a backup or guarantee that it survives deletion of the host or its underlying disk.

This guide explains the storage choices, demonstrates a small persistence check, and separates routine container replacement from data deletion. The examples use Linux containers and disposable test data. Check the Docker host and volume name before running them.

Choose between a volume, a bind mount, and the container layer

Docker's storage overview separates application data from the storage used for container images and writable layers. Files left only in a container's writable layer disappear when that container is removed. Stopping a container is different: its layer remains available when the same container starts again.

  • Named volume: use a recognizable Docker-managed name for application data that must outlive an individual container.
  • Bind mount: use a specific host path when host tools and a container need access to the same files, such as source code or configuration.
  • Temporary memory storage: consider tmpfs for suitable disposable runtime data, after reviewing its limits. It is not persistent storage.

A default local volume belongs to the Docker daemon host. A new VM does not automatically acquire it. Network storage and volume plugins have their own setup, access, and failure behavior. On a cloud VM, verify the provider's disk lifecycle separately; a Docker storage setting cannot establish it.

Understand names, paths, and mount behavior

An anonymous volume receives a generated name. It is harder to identify and is not automatically reused by every new container. With docker run --rm, associated anonymous volumes are normally removed when the container exits, while named volumes remain. Prefer explicit names for data you intend to reuse.

A mount can hide files already present at the container's target path. An empty volume may receive a copy of existing image files at that path; volume-nocopy disables that initialization. A nonempty volume is not refreshed from a new image. Docker's volume mount documentation explains these behaviors. Check the application's documented data path instead of guessing it from an older image version.

Bind mounts refer to paths on the daemon host, which may differ from the computer running the Docker client. They are writable by default, so a container can modify host files. Use read-only access when possible. By default, --mount reports a missing bind source rather than silently creating a directory; the shorter -v syntax can create one.

Create a named volume and check persistence

Use a nonproduction Docker host with permission to run Linux containers. The current context helps identify the selected environment. Confirm the server is reachable and inspect existing volume names:

docker context show
docker version
docker compose version
docker volume ls

Stop if the context is unexpected or the server connection fails. Choose a fresh name if volume-demo-20261030 already exists. docker volume create can reuse a name already present on the same driver; it does not promise a new empty volume.

docker volume create volume-demo-20261030
docker volume inspect volume-demo-20261030

The inspection result identifies the name, driver, options, and mountpoint. Check those details, but access the data through a mounted container. Do not edit Docker's internal volume directory directly.

Write one known value using a temporary container. The command may pull the Alpine image if it is absent. It needs no published ports or container network access:

docker run --rm --network none --mount type=volume,src=volume-demo-20261030,dst=/data alpine:3.22 sh -c "printf '%s\n' volume-check > /data/note.txt"

After that command exits successfully, its container is removed. Start a different container with the same named volume, this time mounted read-only:

docker run --rm --network none --mount type=volume,src=volume-demo-20261030,dst=/data,readonly alpine:3.22 cat /data/note.txt

The expected output is volume-check. This is a focused check that a file can be read after replacement of the writing container, following Docker's persistence model. It does not test host failure, backup recovery, or database consistency. Stop and investigate any nonzero exit status instead of continuing through the examples.

The example uses alpine:3.22, a release branch listed in Alpine's support schedule. A tag can receive updates. For a controlled production procedure, choose and record an approved image digest and maintain it through your normal update process.

Mount the existing volume in Docker Compose

Save the following as compose.yaml in a new test directory. The service reads the file created above. The long mount syntax makes its type, source, target, and read-only access explicit:

services:
  reader:
    image: alpine:3.22
    network_mode: none
    command: ["cat", "/data/note.txt"]
    volumes:
      - type: volume
        source: demo-data
        target: /data
        read_only: true

volumes:
  demo-data:
    external: true
    name: volume-demo-20261030

The top-level demo-data key is a Compose reference. The name field selects the actual Docker volume. With external: true, Compose expects it to exist and does not create it. This setting describes lifecycle ownership; it does not mean remote storage or an independent backup.

First validate the configuration, then use a one-off Compose run. Execute the second command only if validation succeeds:

docker compose -p volume-lab-20261030 -f compose.yaml config --quiet
docker compose -p volume-lab-20261030 -f compose.yaml run --rm reader

The reader should print the same value. For an ordinary application, the Compose service would instead use its real image and data directory. Without an explicit name, Compose normally scopes a managed volume to its project. A changed project name can select a different volume and make an application appear empty; inspect the actual attachment before trying to restore or delete anything.

Plan backups around the application

Mounting a source read-only protects it from the backup container's writes. It does not stop another container from changing that source during a copy. A successful archive command can therefore capture an inconsistent set of application files.

For a database, use its supported backup method or coordinate a consistent snapshot. PostgreSQL's file-system backup rules, for example, explain why an ordinary copy of a running data directory is insufficient. Treat shutdown and snapshots as application procedures, not generic Docker fixes.

Record what must be recovered: data files, application version, configuration, ownership, permissions, and any keys or external dependencies. Keep an independently protected copy with a defined retention policy. Our cloud backup guide covers that wider plan.

Restore into a new test volume and an isolated application instance. Check known records, file permissions, and application behavior. Measure the time required to recover. Our recoverability testing guide helps turn those checks into acceptance criteria.

Know which cleanup actions remove data

Ordinary docker compose down removes the project's containers and networks, while managed named volumes remain by default. Adding --volumes removes declared managed volumes and attached anonymous volumes. External volumes are excluded from Compose removal, but they can still be deleted through other tools.

docker volume prune currently targets unused anonymous local volumes by default; --all also includes unused named volumes. Unused means no container references the volume, not that its contents are worthless. docker system prune --volumes has a different scope. Read the exact command's documentation and warning before any cleanup.

Only after confirming that this exercise's volume contains disposable data and no application needs it, remove that exact name with docker volume rm:

docker volume rm volume-demo-20261030

Do not replace the name with a production volume or add a force option to bypass an unexpected error. For ongoing workloads, assign an owner to each volume and document its application, backup location, and deletion policy. A storage name tells you where to look; a tested recovery process tells you whether the data can be recovered.

Your next workload belongs on Hivenet.

Pick one AI, compute, or storage workload and see the difference for yourself. Spin it up in minutes, or let our team map your fastest path to production.