Docker Volumes and Data Persistence Explained
In this tutorial, you'll learn about Docker Volumes and Data Persistence Explained. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
What You'll Learn
Manage data in Docker containers — volumes, bind mounts, and how to persist, share, and back up data across container lifecycles.
Why It Matters
Containers are ephemeral by design. Without volumes, all data is lost when a container stops. Volumes are essential for databases, file uploads, and logs.
Real-World Use
Persisting PostgreSQL data across restarts, sharing source code between host and container for development, or storing uploads separately from application code.
The Data Problem
Container starts → writes data → container stops → DATA LOST
Volumes solve this by storing data outside the container's writable layer.
Three Types of Mounts
| Type | Managed By | Use Case | Persistence |
|---|---|---|---|
| Volume | Docker | Production data, backups | Survives container removal |
| Bind mount | You | Development, config files | Survives container removal |
| tmpfs | Memory only | Secrets, temp data | Lost on container stop |
Named Volumes (Recommended)
Docker manages the storage location:
# Create a volume
docker volume create postgres-data
# Mount it
docker run -d \
--name db \
-v postgres-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16
# Even if container is removed, data persists
docker rm -f db
# Create a new container with same volume
docker run -d \
--name db2 \
-v postgres-data:/var/lib/postgresql/data \
postgres:16
# All previous data is still there
Bind Mounts
Map a host directory into the container:
# Development: live-reload source code
docker run -d \
-p 3000:3000 \
-v $(pwd)/src:/app/src \
node:20-alpine \
npm run dev
# Mount config file
docker run -d \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:alpine
Watch out: Bind mounts can overwrite container files. Use :ro for read-only.
tmpfs Mounts
Data stored in memory, never written to disk:
docker run -d \
--tmpfs /app/temp:noexec,nosuid,size=64m \
nginx:alpine
# Good for:
# - API tokens
# - Session data
# - Temporary cached files
Volumes in Docker Compose
services:
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
environment:
POSTGRES_PASSWORD: secret
app:
build: .
volumes:
- ./src:/app/src # Bind mount for dev
- uploads:/app/uploads # Named volume
ports:
- "3000:3000"
volumes:
pgdata:
uploads:
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 \
tar xzf /backup/pgdata-backup.tar.gz -C /target
# Copy between containers
docker run --rm \
-v source-volume:/from \
-v target-volume:/to \
alpine \
sh -c "cp -a /from/. /to/"
Common Patterns
Development
# Bind mount source code, named volume for node_modules
docker run -d \
-v $(pwd):/app \
-v /app/node_modules \ # Anonymous volume prevents overwrite
-p 3000:3000 \
node:20-alpine \
npm run dev
Production
# Use named volumes, avoid bind mounts
volumes:
- data:/data
- config:/etc/app/config:ro
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro