Docker Volumes Guide

By default, data inside a container is ephemeral—it disappears when the container stops. Docker volumes provide persistent storage that survives container lifecycle. This guide covers named volumes, bind mounts, tmpfs mounts, and volume management best practices.

Named Volumes Bind Mounts tmpfs
Why Do We Need Volumes?

Containers are designed to be ephemeral—you can stop, delete, and recreate them at any time. When a container is deleted, all data stored in its writable layer is lost. This is problematic for databases, user uploads, logs, configuration files, and any other data that must persist beyond a container's lifetime.

Docker volumes solve this problem by providing storage that exists independently of containers. Volumes can be shared between multiple containers, backed up, migrated, and managed separately from the containers that use them. Docker supports three main types of mounts: named volumes (managed by Docker), bind mounts (host directories), and tmpfs mounts (in-memory storage).

Always use volumes for persistent data. Never store important data only in a container's writable layer—it will be lost when the container is removed.
Volume Types at a Glance
FeatureNamed VolumesBind Mountstmpfs
Managed byDockerUser (host filesystem)Memory (RAM)
PersistenceYesYesNo (in-memory only)
PerformanceGoodBest (native)Fastest
Backup/RestoreEasyManualN/A
Use CaseDatabases, production dataDevelopment, config filesTemporary, sensitive data
Cross-platformYesPaths differLinux only
Named Volumes (Docker Managed)

Named volumes are created and managed by Docker. They are stored in Docker's storage directory (usually /var/lib/docker/volumes/ on Linux). Named volumes are the recommended way to persist data in production because they are portable, can be backed up, and are managed by Docker commands.

Benefits of named volumes: Docker handles permissions automatically, they work the same on all platforms, they can be backed up and restored using Docker commands, and they can be shared between multiple containers.

# Create a named volume docker volume create postgres_data # List volumes docker volume ls # Inspect a volume docker volume inspect postgres_data # Run container with named volume docker run -d \ --name postgres \ -v postgres_data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgres:15 # Using --mount syntax (more explicit) docker run -d \ --name postgres \ --mount type=volume,source=postgres_data,target=/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=secret \ postgres:15 # Data persists even after container deletion docker stop postgres docker rm postgres docker run -d --name new-postgres -v postgres_data:/var/lib/postgresql/data postgres:15 # Data is still there!
Bind Mounts (Host Directory)

Bind mounts map a directory from the host filesystem directly into the container. They are the preferred choice for development because they allow you to edit code on the host and see changes instantly in the container (hot reload). Bind mounts are also useful for providing configuration files or sharing the Docker socket.

However, bind mounts are less portable than named volumes because they depend on host directory paths. They also expose host filesystem permissions issues—the container must have appropriate permissions to read/write the host directory.

# Bind mount current directory to /app in container docker run -d \ --name dev \ -v "$PWD":/app \ -w /app \ node:18 npm run dev # Using --mount syntax (more explicit) docker run -d \ --name dev \ --mount type=bind,source="$(pwd)",target=/app \ -w /app \ node:18 npm run dev # Read-only bind mount (prevent container from writing) docker run -d \ --name nginx \ -v "$PWD/nginx.conf":/etc/nginx/nginx.conf:ro \ nginx # Mount single file docker run -it --rm \ -v "$PWD/config.json":/app/config.json:ro \ alpine cat /app/config.json
Bind mounts are perfect for development! Edit code on your host, and the container sees changes immediately (for interpreted languages with hot reload).
tmpfs Mounts (In-Memory Storage)

tmpfs mounts store data in the host's memory (RAM), not on disk. This is extremely fast but data is lost when the container stops. tmpfs is perfect for temporary, sensitive data that shouldn't be persisted or written to disk—like session tokens, cache, or temporary files.

Important: tmpfs only works on Linux hosts. On Docker Desktop, it falls back to disk-based storage. tmpfs mounts cannot be shared between containers.

# Run container with tmpfs mount docker run -d \ --name cache \ --tmpfs /app/cache:rw,noexec,nosuid,size=100m \ redis # Using --mount syntax docker run -d \ --name cache \ --mount type=tmpfs,destination=/app/cache,tmpfs-size=100M,tmpfs-mode=1777 \ redis # Multiple tmpfs mounts docker run -d \ --name app \ --tmpfs /tmp:rw,size=50m \ --tmpfs /dev/shm:rw,size=1g \ myapp # Verify mount docker exec cache df -h | grep /app/cache
tmpfs data is stored in RAM. If the container uses too much tmpfs space, it could consume host memory and affect other processes. Set appropriate size limits with the `size` option.
Volume Management Commands
# Create a volume docker volume create mydata # List volumes docker volume ls # Inspect volume (shows mountpoint on host) docker volume inspect mydata # Remove a volume (only if not in use) docker volume rm mydata # Remove all unused volumes docker volume prune # Remove all volumes (including used - dangerous!) docker volume prune -a # Copy data into a volume using a temporary container docker run --rm -v mydata:/data alpine cp /tmp/data.txt /data/ # Backup a volume docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/mydata-backup.tar.gz /data # Restore a volume from backup docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar xzf /backup/mydata-backup.tar.gz -C /
Volumes in Docker Compose
# docker-compose.yml version: '3.8' volumes: postgres_data: driver: local redis_data: services: postgres: image: postgres:15 volumes: - postgres_data:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro environment: POSTGRES_PASSWORD: secret redis: image: redis:alpine volumes: - redis_data:/data command: redis-server --appendonly yes app: image: myapp volumes: - ./src:/app/src:ro - /app/node_modules # Anonymous volume (Docker managed) - type: tmpfs target: /app/tmp tmpfs: size: 100M dev: image: node:18 working_dir: /app volumes: - .:/app - /app/node_modules # Prevents overwriting container's node_modules command: npm run dev
Sharing Volumes Between Containers

Volumes can be shared between multiple containers. This is useful for patterns like web server + file uploader, or log aggregator + log writer. The same volume can be mounted into many containers simultaneously.

# Create shared volume docker volume create shared_data # Container A writes to volume docker run -d --name writer -v shared_data:/data alpine \ sh -c "while true; do echo $(date) >> /data/log.txt; sleep 5; done" # Container B reads from same volume docker run -it --rm --name reader -v shared_data:/data alpine cat /data/log.txt # Container C also writes to same volume docker run -d --name logger -v shared_data:/logs alpine \ sh -c "while true; do echo 'Log entry' >> /logs/app.log; sleep 10; done" # All three containers see the same files
Volume Drivers: NFS, S3, Cloud Storage

Docker supports volume drivers that allow storing data on remote systems: NFS, AWS EBS, Azure File Storage, Google Cloud Storage, and more. This enables stateful containers in clustered environments where containers can move between hosts while preserving data.

# Create NFS volume docker volume create \ --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.100,rw \ --opt device=:/exported/path \ nfs-volume # Run container with NFS volume docker run -d --name app -v nfs-volume:/data myapp # AWS EBS volume (using rexray driver) docker volume create \ --driver rexray/ebs \ --opt size=10 \ --opt volumetype=gp2 \ ebs-volume # Run container with cloud volume docker run -d --name db -v ebs-volume:/var/lib/mysql mysql
Volume Best Practices
  • Use named volumes for production data - They are portable, backup-friendly, and managed by Docker.
  • Use bind mounts for development - Code changes on host reflect instantly in containers.
  • Never store important data only in containers - Always use volumes for databases, uploads, logs.
  • Use .dockerignore for bind mounts - Prevent accidentally copying node_modules or secrets into containers.
  • Use tmpfs for sensitive temporary data - Session tokens, cache, temporary files that shouldn't hit disk.
  • Back up volumes regularly - Use the backup/restore patterns shown above.
  • Remove unused volumes - Use docker volume prune to free disk space.
  • Use volume drivers for clustered environments - NFS or cloud storage for multi-host persistence.
Frequently Asked Questions
What's the difference between a volume and a bind mount?
Volumes are managed by Docker, stored in Docker's directory, and portable across systems. Bind mounts map any host directory directly into the container and are host-path dependent. For production, use volumes; for development, bind mounts are convenient.
Does deleting a container delete the volume?
No! Volumes exist independently of containers. When you run `docker rm container`, the volume persists unless you use `-v` flag. Use `docker volume rm volume-name` to delete volumes.
Where are Docker volumes stored on disk?
On Linux: `/var/lib/docker/volumes/`. On Docker Desktop: inside the VM (macOS/Windows). Use `docker volume inspect volume-name` to see the exact path.
Can I mount a file, not just a directory?
Yes! Both named volumes and bind mounts can mount individual files. For bind mounts: `-v /host/file.conf:/container/file.conf`. For volumes, the file must already exist in the volume.
How do I make a volume read-only?
Add `:ro` to the mount specification. Example: `-v mydata:/data:ro`. The container can read but not write to the volume.
What's the difference between VOLUME in Dockerfile and -v?
`VOLUME` in Dockerfile creates an anonymous volume at the specified path, but you cannot control the host location. Using `-v` at runtime gives you control over volume name and host path. For production, use runtime `-v` or `--mount`.
Can I share a volume across multiple Docker hosts?
Yes, using volume drivers (NFS, EBS, etc.) or Swarm's built-in volume support. Standard local volumes are host-specific and cannot be shared across hosts.
How do I copy data from host into a volume?
Use a temporary container: `docker run --rm -v myvolume:/target -v $(pwd):/source alpine cp /source/data.txt /target/`
Previous: Port Mapping & Expose Next: Bind Mounts vs Volumes

Docker volumes are essential for persistent data in containerized applications. Choose named volumes for production, bind mounts for development, and tmpfs for temporary in-memory storage.