docker
Docker Volumes: Persistent Storage Solutions
Beginner
12 minutes
October 2026
CloudOpsGuide Team
Docker Volumes: Persistent Storage Solutions
Manage persistent data in Docker containers — named volumes, bind mounts, tmpfs, and best practices for production workloads.
Table of Contents
- Volume Types
- Named Volumes
- Bind Mounts
- tmpfs Mounts
- Docker Compose Volumes
- Backup and Restore
- Best Practices
Volume Types
| Type | Data Location | Persistence | Use Case |
|---|---|---|---|
| Named Volume | Docker-managed (/var/lib/docker/volumes) | Survives container deletion | Databases, app data |
| Bind Mount | Specific host path | Depends on host | Config files, source code |
| tmpfs | Host RAM only | Gone on stop | Temporary sensitive data |
Named Volumes
Create and Use
# Create a named volume
docker volume create my-data
# Use it
docker run -d --name db -v my-data:/var/lib/postgresql/data postgres:16
# Inspect
docker volume inspect my-data
Docker Compose
services:
db:
image: postgres:16
volumes:
- dbdata:/var/lib/postgresql/data
volumes:
dbdata: # Docker creates and manages this
Drivers
# Local driver (default)
docker volume create my-data
# NFS driver
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/exports/data \
nfs-data
# Azure Files (via plugin)
docker volume create --driver azure_file_storage azure-data
Bind Mounts
# Bind mount — host path to container path
docker run -d --name nginx \
-v /home/user/html:/usr/share/nginx/html:ro \
nginx:alpine
Read-Only vs Read-Write
# Read-only — container can't modify files
-v /host/path:/container/path:ro
# Read-write (default)
-v /host/path:/container/path:rw
Common Use Cases
# Source code for development
docker run -v $(pwd)/src:/app/src node:20 npm run dev
# Config files
docker run -v ./nginx.conf:/etc/nginx/nginx.conf:ro nginx
# Logs to host
docker run -v ./logs:/var/log/app myapp
tmpfs Mounts
# Store sensitive data in RAM only — never touches disk
docker run -d --name app \
--tmpfs /tmp/secrets \
myapp
Use for: temporary credentials, session data, cache that must not persist.
Docker Compose Volumes
Named + Bind + tmpfs Together
services:
app:
image: myapp
volumes:
- app-data:/app/data # named volume (persistent)
- ./config:/app/config:ro # bind mount (config)
- type: tmpfs
target: /tmp/cache # tmpfs (temporary)
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
shared:
image: alpine
volumes:
- shared-data:/shared
volumes:
app-data:
db-data:
shared-data:
Volume From Another Container
services:
backup:
image: alpine
volumes:
- db-data:/backup:ro # read-only access to db's volume
command: tar czf /backup/backup.tar.gz -C /backup .
Backup and Restore
Backup a Named Volume
# Create a backup of a named volume
docker run --rm \
-v db-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/db-backup-$(date +%Y%m%d).tar.gz -C /source .
Restore to a New Volume
docker volume create db-data-restored
docker run --rm \
-v db-data-restored:/target \
-v $(pwd):/backup \
alpine sh -c "cd /target && tar xzf /backup/db-backup-20261007.tar.gz"
Backup Running Container's Data
# Stop the container first for consistency
docker stop db
docker run --rm -v db-data:/source:ro -v $(pwd):/backup alpine tar czf /backup/db.tar.gz -C /source .
docker start db
Best Practices
1. Named Volumes Over Bind Mounts for Production
# Bad — host-dependent, fragile
volumes:
- /home/user/data:/var/lib/postgresql/data
# Good — portable, Docker-managed
volumes:
- pgdata:/var/lib/postgresql/data
2. Read-Only for Config Files
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # can't be modified at runtime
- ./ssl:/etc/ssl/certs:ro
3. Volume Naming Convention
volumes:
- "${APP_NAME}-data:/app/data"
- "${APP_NAME}-logs:/app/logs"
- "${APP_NAME}-config:/app/config:ro"
4. Clean Up Orphaned Volumes
# See unused volumes
docker volume ls -f dangling=true
# Remove unused volumes
docker volume prune
5. Don't Store Logs in Named Volumes
# Bad — logs fill up disk silently
docker run -v app-logs:/var/log/app myapp
# Better — use Docker's logging drivers
docker run --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 myapp
Common Issues
"Permission Denied" on Volume
The container's user can't write to the host directory:
# Fix ownership on host
docker run -v $(pwd)/data:/app/data --user $(id -u):$(id -g) myapp
# Or use named volumes (no permission issues)
docker run -v app-data:/app/data myapp
Volume Size Growing Unbounded
# Check what's using space
docker system df -v | grep volume
# See inside a volume
docker run --rm -v my-volume:/data alpine du -sh /data/* | sort -h
Data Lost After Container Removal
Volumes persist containers — but only if you use -v (named/bind). If you didn't:
# Data is inside the container's writable layer — gone on removal
docker rm my-container # data lost!
# Always use volumes for data
docker run -v my-data:/data myapp
Quick Reference
# List volumes
docker volume ls
# Inspect a volume
docker volume inspect my-data
# Create volume
docker volume create my-data
# Remove specific volume
docker volume rm my-data
# Remove all unused volumes
docker volume prune
# Run with volume
docker run -v name:/path image
# Run with bind mount
docker run -v /host/path:/container/path:ro image
# Run with tmpfs
docker run --tmpfs /tmp image
Related Articles
Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Beginner
Estimated Reading Time: 12 minutes