Docker Volumes

Persist container data with Docker volumes, bind mounts, and tmpfs mounts, and learn when to use each, with backup and Compose examples.

By default, everything a container writes goes into its writable layer, which is deleted when the container is removed. Volumes and mounts let data live outside the container so it survives restarts, upgrades, and replacement. Getting storage right is essential for databases, uploads, and any stateful workload.

The Three Mount Types

Aspect Volume Bind mount tmpfs mount
Storage location Managed by Docker (/var/lib/docker/volumes/... on Linux) Any host path you specify Host memory only
Created by docker volume create or automatically You, on the host Docker at container start
Survives container removal Yes Yes (it is your host directory) No
Portability High, independent of host layout Depends on host path existing Not applicable
Typical use Databases, persistent app data Source code in development, config files Secrets or scratch data that must not touch disk
Pre-populated from image Yes, for new empty volumes No, host content hides the image content No
Works on Linux only No No Yes (Linux containers)

Named Volumes

# Create a volume and use it for PostgreSQL data
docker volume create pgdata

docker run -d --name db \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# Remove the container; the data remains
docker rm -f db

# Start a new container with the same data
docker run -d --name db2 \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

docker volume ls
# DRIVER    VOLUME NAME
# local     pgdata

docker volume inspect pgdata
# "Mountpoint": "/var/lib/docker/volumes/pgdata/_data"

If you use -v name:/path and the volume does not exist, Docker creates it automatically. Volumes can be shared by several containers.

Bind Mounts

A bind mount maps an existing host file or directory into the container. It is useful in development so code changes appear instantly.

docker run -d --name web -p 8080:80 \
  -v "$(pwd)/site:/usr/share/nginx/html:ro" \
  nginx:1.27

:ro makes the mount read-only inside the container. The --mount syntax is more explicit and recommended for clarity:

docker run -d --name web -p 8080:80 \
  --mount type=bind,source="$(pwd)/site",target=/usr/share/nginx/html,readonly \
  nginx:1.27

docker run -d --name db \
  --mount type=volume,source=pgdata,target=/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret postgres:16

With -v, a missing host path is created as a directory automatically; with --mount type=bind Docker returns an error instead, which catches typos.

tmpfs Mounts

docker run -d --name cache \
  --tmpfs /tmp:rw,size=64m \
  nginx:1.27

Data in a tmpfs mount lives in memory and disappears when the container stops.

Volumes in Docker Compose

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

  web:
    image: nginx:1.27
    volumes:
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

Named volumes are declared in the top-level volumes: key. docker compose down keeps them; docker compose down -v deletes them.

Backing Up and Restoring a Volume

Use a temporary container that mounts the volume and a host directory:

# Backup
docker run --rm \
  -v pgdata:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

# Restore into a new volume
docker volume create pgdata_restored
docker run --rm \
  -v pgdata_restored:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

For databases, a logical backup such as pg_dump is safer than copying files from a running instance.

Anonymous Volumes and the VOLUME Instruction

A VOLUME /data instruction in a Dockerfile (or -v /data at run time) creates an anonymous volume with a random name if you do not mount anything there. These are easy to lose track of and pile up. Prefer explicit named volumes.

docker volume ls -f dangling=true     # volumes not used by any container
docker volume prune                   # remove unused local volumes

Common Mistakes

  • Keeping database data in the container layer. Removing the container deletes it. Mount a volume.
  • Bind-mounting over image content unintentionally. A bind mount hides whatever the image had at that path, such as installed dependencies in node_modules.
  • Permission problems with bind mounts. The container user's UID and GID must be able to read and write the host path.
  • Running docker volume prune or docker compose down -v without checking. Both permanently delete data.
  • Relying on anonymous volumes. They are hard to identify and are often left behind.

Best Practices

  • Use named volumes for persistent application data and bind mounts for development source code.
  • Prefer the --mount syntax in scripts for explicit, strict behaviour.
  • Mount configuration and secrets as read-only (:ro) wherever possible.
  • Back up volumes regularly and test restores.
  • Keep containers stateless so they can be replaced freely.

Interview Questions

1. What is the difference between a volume and a bind mount?

A volume is created and managed by Docker in its own storage area and is independent of the host's directory layout. A bind mount maps a specific host path into the container. Volumes are preferred for production data and are portable; bind mounts suit development and sharing host config files.

2. How do you persist data for a database container?

Mount a named volume at the database's data directory, for example -v pgdata:/var/lib/postgresql/data for PostgreSQL. The data then outlives the container and can be attached to a new container.

3. What happens to a volume when the container is removed?

It stays. docker rm does not delete named volumes. Anonymous volumes are only removed with docker rm -v or when started with --rm. Explicit removal needs docker volume rm or docker volume prune.

4. What is a tmpfs mount and when would you use it?

A tmpfs mount stores data in host memory and never writes it to disk. It is useful for temporary or sensitive data that must not persist, and it disappears when the container stops.

5. How can multiple containers share data?

Mount the same named volume into each container. For concurrent writers you must ensure the application handles locking itself, since Docker does not coordinate access.

6. How would you back up a Docker volume?

Start a short-lived container that mounts the volume read-only plus a host directory, then archive the contents with tar. For databases prefer native tools such as pg_dump for consistency.

Summary

  • Container writable layers are temporary; use volumes for persistent data.
  • Named volumes are Docker-managed and portable; bind mounts map host paths; tmpfs is memory-only.
  • --mount is explicit and stricter than -v.
  • docker compose down -v and volume pruning delete data permanently.

Continue Learning

Previous: Docker Commands | Next: Docker Networking

Was this guide helpful?

CodeWithVenu is free to read, with no paywall. If this guide saved you time or helped you prepare, a small voluntary contribution helps me write more practical tutorials, architecture guides, and interview-prep content.