Volumes, bind mounts, tmpfs — data persistence patterns, backups, and real-world usage.
By default, container data is stored in the container's writable layer and lost when the container is removed. Docker provides three mount types for persistent storage: volumes, bind mounts, and tmpfs mounts.
Data survives container restarts and deletions when stored in volumes or bind mounts.
Container storage layer is isolated from volumes - data doesn't count toward container size.
Multiple containers can mount the same volume simultaneously for data sharing.
Volumes offer native disk performance. tmpfs offers RAM speed. Bind mounts vary by platform.
Docker CLI commands manage volumes. Host OS manages bind mount directories.
Volumes work consistently across Docker hosts. Bind mounts depend on host filesystem structure.
# Create a volume
docker volume create my-volume
# List all volumes
docker volume ls
# Inspect volume details
docker volume inspect my-volume
# Remove a volume
docker volume rm my-volume
# Remove all unused volumes
docker volume prune
# Run container with volume
docker run -v my-volume:/app/data nginx
# Run container with bind mount
docker run -v /host/path:/container/path nginx
Volumes are the preferred mechanism for persisting data in Docker. They're completely managed by
Docker,
stored in a dedicated directory on the host (/var/lib/docker/volumes/ on Linux),
and isolated from core host functionality.
Created explicitly with docker volume create or automatically when container starts with -v flag.
Docker handles storage location, permissions, and lifecycle independently of containers.
Volume mounted to specific directory inside container. Multiple containers can share same volume.
Data remains even after container deletion. Must explicitly run docker volume rm to delete.
Named volumes have user-defined names. Anonymous volumes get random UUIDs.
If mount point contains data in image, that data is copied to new volume on first mount.
# Create named volume
docker volume create postgres-data
# Run container with named volume
docker run -d --name db \
-v postgres-data:/var/lib/postgresql/data \
postgres:latest
# Anonymous volume (auto-created)
docker run -d -v /app/data nginx
# Using --mount (long syntax, more explicit)
docker run -d --name web \
--mount source=web-data,target=/usr/share/nginx/html \
nginx
# Inspect volume location
docker volume inspect postgres-data
# Share volume between containers
docker run -d --name app1 -v shared-data:/data alpine
docker run -d --name app2 -v shared-data:/data alpine
# Read-only volume mount
docker run -d -v my-volume:/data:ro nginx
PostgreSQL, MySQL, MongoDB - persist database files across container restarts.
User uploads, generated files, caches that must survive container updates.
Multiple containers accessing same data - logs, shared configs, file processing.
Centralized location for backing up critical application data.
Bind mounts link a specific file or directory on the host to a container location. They provide direct, immediate synchronization between host and container filesystems. Ideal for development workflows where you need real-time code updates without rebuilding images.
Specific host path mapped directly to container path. Must use absolute paths.
Changes on host appear instantly in container and vice versa. No copy operation.
Requires exact path to exist on host. Not managed by Docker.
Host file permissions apply. Container processes must have appropriate access rights.
If mount path contains data in image, host directory content takes precedence.
Performance varies by platform. Slower on Docker Desktop (Mac/Windows) due to filesystem translation.
# Basic bind mount (short syntax)
docker run -d -v /host/path:/container/path nginx
# Development: Mount source code
docker run -d --name dev-app \
-v $(pwd)/src:/app/src \
-p 3000:3000 \
node:latest
# Mount single config file
docker run -d \
-v /home/user/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx
# Using --mount (long syntax, more explicit)
docker run -d \
--mount type=bind,source=/host/data,target=/app/data \
alpine
# Read-only bind mount
docker run -d -v /host/config:/app/config:ro nginx
# Mount with propagation mode
docker run -d \
--mount type=bind,source=/host/data,target=/data,bind-propagation=shared \
ubuntu
Mount source code for live reload without rebuilding images. Edit locally, run in container.
Inject host configs into containers. Update configs without container restart.
Write container logs to host directory for easy monitoring and analysis.
Share Docker socket (/var/run/docker.sock) or other host resources with containers.
| Scenario | Use Bind Mount | Use Volume |
|---|---|---|
| Development | ✓ Source code sync | Database data |
| Production | Config files only | ✓ All persistent data |
| Host Integration | ✓ Need host tools/files | Isolated storage |
| Performance | Linux hosts only | ✓ All platforms |
| Portability | Low | ✓ High |
tmpfs mounts store data in the host system's memory (RAM) only. They provide the fastest I/O performance but are temporary - all data is lost when the container stops. Perfect for sensitive information that shouldn't be persisted to disk or temporary caches requiring maximum speed.
Data stored entirely in host's RAM. No disk I/O - fastest possible performance.
All data automatically deleted when container stops. Perfect for temporary files.
Limited by available system memory. Can set explicit size limits to prevent OOM issues.
Zero disk footprint. Data never written to storage layer. Automatic cleanup.
Sensitive data never hits disk. Reduces risk of data leaks from disk forensics.
Linux only. Uses native tmpfs filesystem. Not available on Docker Desktop.
# Basic tmpfs mount (short syntax)
docker run -d --tmpfs /app/cache nginx
# tmpfs with size limit (default unlimited)
docker run -d --tmpfs /tmp:rw,size=100m,mode=1777 nginx
# Using --mount (long syntax, more options)
docker run -d \
--mount type=tmpfs,destination=/app/tmp,tmpfs-size=104857600 \
ubuntu
# tmpfs with specific mode (permissions)
docker run -d \
--mount type=tmpfs,destination=/run/secrets,tmpfs-mode=1700 \
alpine
# Multiple tmpfs mounts
docker run -d \
--tmpfs /tmp \
--tmpfs /app/cache:rw,size=50m \
nginx
# Verify tmpfs mount
docker exec container-name df -h /app/cache
| Option | Description | Example |
|---|---|---|
| tmpfs-size | Size limit in bytes (default: unlimited) | tmpfs-size=104857600 (100MB) |
| tmpfs-mode | File mode in octal (default: 1777) | tmpfs-mode=1700 (owner only) |
| rw / ro | Read-write or read-only | --tmpfs /tmp:ro |
Store API keys, passwords, tokens temporarily. Never written to disk.
User sessions, temporary auth tokens. Fast access, automatic expiry.
Application caches requiring maximum I/O speed. RAM latency vs disk.
Temporary compilation outputs, intermediate files during build processes.
Temporary test files that don't need persistence. Clean slate every run.
Container-specific temporary storage for memory-intensive operations.
Volume drivers extend Docker's storage capabilities beyond local filesystem. They enable volumes to be stored on remote hosts, cloud storage, network filesystems, and specialized storage systems. Critical for production deployments requiring high availability, backup, and distributed storage.
| Driver | Storage Backend | Use Case |
|---|---|---|
| local | Host filesystem | Default - single-host deployments |
| nfs | Network File System | Shared storage across multiple hosts |
| rexray/ebs | AWS Elastic Block Store | AWS cloud persistent storage |
| azure-file | Azure File Storage | Microsoft Azure cloud storage |
| gce-docker | Google Persistent Disk | Google Cloud Platform storage |
| vieux/sshfs | SSH Filesystem | Remote host storage via SSH |
| convoy | Multiple backends | Backup, snapshot, restore features |
| portworx | Distributed storage | Enterprise container storage platform |
Stores volumes in /var/lib/docker/volumes/ with simple directory structure.
Supports type, device, and o parameters for advanced local mounting.
Local driver can mount NFS shares as Docker volumes.
Can mount Windows shares (CIFS) using local driver with options.
# Default local driver (implicit)
docker volume create my-volume
# Explicit local driver
docker volume create --driver local my-local-volume
# NFS volume using local driver
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/dir \
nfs-volume
# CIFS/SMB volume
docker volume create --driver local \
--opt type=cifs \
--opt device=//server/share \
--opt o=username=user,password=pass \
smb-volume
# AWS EBS with RexRay driver
docker volume create --driver rexray/ebs \
--name my-ebs-volume \
--opt size=10
# Run container with driver-based volume
docker run -d -v my-ebs-volume:/data nginx
# List volumes by driver
docker volume ls --filter driver=local
# Install RexRay plugin
docker plugin install rexray/ebs \
EBS_ACCESSKEY=AKIAIOSFODNN7EXAMPLE \
EBS_SECRETKEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Create EBS-backed volume
docker volume create --driver rexray/ebs \
--name postgres-data \
--opt size=20
# Run database with EBS volume
docker run -d --name postgres \
--volume-driver rexray/ebs \
--mount src=postgres-data,target=/var/lib/postgresql/data \
postgres:latest
Docker Swarm or Kubernetes needing shared storage across nodes.
Leverage AWS EBS, Azure Disks, GCP Persistent Disks for cloud-native apps.
Replicated storage backends ensuring data availability during host failures.
Integration with NetApp, EMC, or other enterprise storage systems.
Drivers offering built-in backup, snapshot, and restore capabilities.
SSD-backed cloud storage for high-IOPS database workloads.
Backing up Docker volumes is critical for disaster recovery, data migration, and testing. Docker volumes can be backed up by creating temporary containers that mount the volume and use tar or application-specific tools to create archives.
| Method | Pros | Cons | Best For |
|---|---|---|---|
| Application-Specific | Consistent, tested, reliable | Tool-dependent, requires knowledge | Databases (pg_dump, mysqldump) |
| Volume Copy (tar) | Simple, works for any volume | May be inconsistent, large files | File-based data, static content |
| Volume-to-Volume | Fast, stays in Docker | Still on same host, not true backup | Quick snapshots, testing |
| Third-Party Tools | Automated, scheduled, cloud upload | Additional dependencies | Production environments |
# Backup volume to tar file
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
ubuntu tar czf /backup/my-volume-backup.tar.gz -C /data .
# Alternative: Stop container first for consistency
docker stop my-app
docker run --rm -v my-volume:/data -v $(pwd):/backup \
ubuntu tar czf /backup/my-volume-backup.tar.gz -C /data .
docker start my-app
# Restore volume from tar backup
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
ubuntu bash -c "cd /data && tar xzf /backup/my-volume-backup.tar.gz"
# Verify backup file
tar tzf my-volume-backup.tar.gz | head
# PostgreSQL backup
docker exec postgres-container \
pg_dump -U username dbname > backup.sql
# PostgreSQL backup (all databases)
docker exec postgres-container \
pg_dumpall -U postgres > backup-all.sql
# PostgreSQL restore
docker exec -i postgres-container \
psql -U username dbname < backup.sql
# MySQL backup
docker exec mysql-container \
mysqldump -u root -p'password' dbname > backup.sql
# MySQL restore
docker exec -i mysql-container \
mysql -u root -p'password' dbname < backup.sql
# MongoDB backup
docker exec mongo-container \
mongodump --out /backup --gzip
# MongoDB restore
docker exec mongo-container \
mongorestore --gzip /backup
# Create new volume
docker volume create my-volume-backup
# Copy data from one volume to another
docker run --rm -i -t \
-v my-volume:/from \
-v my-volume-backup:/to \
ubuntu bash -c "cd /from && cp -av . /to"
# Alternative: Use rsync for incremental copies
docker run --rm \
-v my-volume:/source:ro \
-v backup-volume:/dest \
ubuntu rsync -av /source/ /dest/
# Backup to AWS S3
docker run --rm \
-v my-volume:/data:ro \
-e AWS_ACCESS_KEY_ID=your_key \
-e AWS_SECRET_ACCESS_KEY=your_secret \
amazon/aws-cli s3 sync /data s3://my-bucket/backups/$(date +%Y-%m-%d)/
# Backup with encryption to S3
docker run --rm -v my-volume:/data:ro ubuntu tar czf - -C /data . | \
openssl enc -aes-256-cbc -salt -pass pass:mypassword | \
aws s3 cp - s3://my-bucket/backup-$(date +%Y-%m-%d).tar.gz.enc
# Scheduled backup with cron (on host)
# Add to crontab: 0 2 * * * /path/to/backup-script.sh
# backup-script.sh contains backup commands above
Automate backups with cron or orchestration tools. Daily at minimum for production data.
Regularly test restore process. Backups are useless if you can't restore from them.
Store backups on different server or cloud storage. Protect against host failure.
Keep multiple backup versions. Follow 3-2-1 rule: 3 copies, 2 different media, 1 off-site.
Encrypt sensitive data backups before upload. Use tools like gpg or openssl.
Monitor backup job success/failure. Alert on backup failures immediately.
Choose the right mount type based on persistence requirements, performance needs, security constraints, and deployment environment.
| Feature | Volumes | Bind Mounts | tmpfs Mounts |
|---|---|---|---|
| Managed By | Docker | Host OS | Host OS (RAM) |
| Data Persistence | ✓ Yes | ✓ Yes | ✗ No (RAM only) |
| Platform Support | All (Linux, Mac, Windows) | All (Linux, Mac, Windows) | Linux only |
| Performance | Excellent (best on Mac/Win) | Excellent (Linux), Slower (Mac/Win) | Fastest (RAM speed) |
| Path Specification | Volume name only | Absolute host path required | Container path only |
| Pre-population | ✓ From container image | ✗ Host content takes precedence | ✗ Empty on creation |
| Sharing Between Containers | ✓ Easy (name reference) | ✓ Possible (same host path) | ✗ Per-container only |
| Backup/Migration | Easy (Docker CLI) | Depends on host setup | Not applicable (temporary) |
| Security | Good isolation | Exposes host filesystem | Best (never on disk) |
| Volume Drivers | ✓ Supported (NFS, cloud, etc.) | ✗ Not applicable | ✗ Not applicable |
| Portability | High | Low (host-dependent) | Medium (Linux only) |
| Swarm Support | ✓ Yes | Limited | ✓ Yes (per-node) |
| Storage Location | /var/lib/docker/volumes/ | User-defined host path | System memory (RAM) |
Read/Write Performance (Best to Slowest):
*Bind mounts on Docker Desktop use filesystem translation layer (osxfs/grpcfuse) causing significant overhead
| Scenario | Recommended Mount | Why |
|---|---|---|
| Production Database | Volume | Persistence, performance, backup support |
| Node.js Development | Bind Mount | Live code reload, instant changes |
| API Secrets | tmpfs | Security - never persisted to disk |
| Application Logs | Volume or Bind Mount | Volume for isolation, Bind for host access |
| Static Assets (CDN) | Volume | Persistence, can migrate to cloud storage |
| Build Cache | tmpfs or Volume | tmpfs for speed, Volume for persistence |
| Config Files | Bind Mount | Easy updates from host without rebuild |
| User Uploads | Volume (cloud driver) | Scalability, S3/Azure integration |
Question 1: Does data need to persist after container stops?
NO → Use tmpfs (fastest, Linux only)
YES → Continue to Question 2
Question 2: Are you in development or production?
DEVELOPMENT → Bind mount for source code, Volume for databases
PRODUCTION → Use Volume (always)
Question 3: Running on Docker Desktop (Mac/Windows)?
YES → Use Volume (much better performance)
NO → Volume or Bind mount both work well
Question 4: Need to share data between containers?
YES → Use Volume (easy sharing by name)
NO → Any mount type works
Question 5: Need cloud storage integration?
YES → Use Volume with driver plugin (rexray, azure, etc.)
NO → Default local driver is fine