Docker Volumes and Persistent Storage
Manage persistent data in Docker — named volumes, bind mounts, tmpfs, backup strategies, and volume drivers for production.
What you'll learn
- ✓Why containers need external storage for persistent data
- ✓Named volumes vs bind mounts vs tmpfs
- ✓Managing volumes in Docker and Compose
- ✓Backup and restore strategies
Prerequisites
- •Docker basics (running containers)
Containers are ephemeral — when they stop, their filesystem is gone. Volumes persist data beyond the container lifecycle. They are how you keep database files, uploads, and configuration alive.
Three types of storage
Named volumes
Docker manages the storage location. Best for production data.
docker volume create mydata
docker run -v mydata:/var/lib/postgresql/data postgres
Bind mounts
Map a host directory into the container. Best for development.
docker run -v $(pwd)/src:/app/src myapp
tmpfs
In-memory storage. Gone when the container stops. Good for sensitive data.
docker run --tmpfs /tmp myapp
Named volumes in detail
# Create
docker volume create pgdata
# List
docker volume ls
# Inspect
docker volume inspect pgdata
# Remove
docker volume rm pgdata
# Remove all unused volumes
docker volume prune
Using volumes
# Named volume
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16
# Anonymous volume (Docker generates a name)
docker run -d -v /var/lib/postgresql/data postgres:16
Volumes in Docker Compose
services:
postgres:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
api:
build: .
volumes:
- ./src:/app/src # bind mount for development
- node_modules:/app/node_modules # named volume for deps
volumes:
pgdata:
node_modules:
Bind mounts for development
services:
api:
build: .
volumes:
- ./src:/app/src:ro # read-only bind mount
environment:
- NODE_ENV=development
The :ro flag makes the mount read-only inside the container.
Sharing volumes between containers
services:
writer:
image: myapp
volumes:
- shared:/data
reader:
image: myapp
volumes:
- shared:/data:ro
volumes:
shared:
Backup and restore
Backup a volume
docker run --rm -v pgdata:/source -v $(pwd):/backup alpine \
tar czf /backup/pgdata-backup.tar.gz -C /source .
Restore a volume
docker run --rm -v pgdata:/target -v $(pwd):/backup alpine \
sh -c "cd /target && tar xzf /backup/pgdata-backup.tar.gz"
Volume permissions
A common issue: the container user does not have permission to write to the volume.
FROM node:20
RUN mkdir -p /app/data && chown -R node:node /app/data
USER node
VOLUME /app/data
Volume drivers
For production, use volume drivers for cloud storage:
# AWS EFS
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=fs-123.efs.us-east-1.amazonaws.com,rw \
--opt device=:/ \
efs-data
Summary
Use named volumes for production data (databases, uploads). Use bind mounts for development (live code reload). Use tmpfs for sensitive temporary data. Back up volumes regularly and use read-only mounts where possible. Volumes are the bridge between Docker’s ephemeral containers and your persistent data.
Related articles
- Docker Docker tmpfs Mounts and In-Memory Storage
Use Docker tmpfs mounts to store sensitive or ephemeral data in memory, keeping it off disk and out of container layers entirely.
- Docker Docker Overlay Filesystem Explained: Layers, lowerdir, upperdir
How Docker's overlay2 storage driver stacks read-only image layers under a writable container layer. Learn the directory anatomy and the copy-on-write behavior.
- Docker Docker Volumes vs Bind Mounts Explained
The practical differences between Docker volumes and bind mounts, when to pick each, and how to avoid the permission and performance traps.
- Docker Docker Compose for Multi-Container Apps
Learn Docker Compose by building a small two-service app — a web API and a Postgres database — defined in a single compose.yaml file and started with one command.