Volume Management
Volumes are Docker's recommended mechanism for persisting data. Unlike data written to the container's writable layer, volume data survives container removal and can be shared between containers. This lesson covers creating, inspecting, and managing all three mount types.
Mount Types at a Glance
flowchart LR
subgraph host["Host Machine"]
V["/var/lib/docker/volumes/\n(Docker-managed)"]
B["/home/user/project/\n(Your directory)"]
T["RAM\n(Memory)"]
end
subgraph container["Container"]
CV["/data"]
CB["/app"]
CT["/tmp/secrets"]
end
V <-->|"Volume"| CV
B <-->|"Bind Mount"| CB
T <-->|"tmpfs"| CT
style V fill:#e8f5e9,stroke:#2e7d32
style B fill:#e3f2fd,stroke:#1565c0
style T fill:#fff3e0,stroke:#ef6c00
| Feature | Named Volume | Bind Mount | tmpfs |
|---|---|---|---|
| Location | Docker-managed directory | Any host path | Memory (RAM) |
| Created by | docker volume create or auto | User specifies path | --tmpfs flag |
| Content on first use | Populated from image | Host directory content | Empty |
| Portable across hosts | ✅ Easy (backup/restore) | ❌ Path-dependent | ❌ Not persisted |
| Managed by Docker | ✅ Yes | ❌ No | ❌ No |
| Performance | Native | Native | Very fast (RAM) |
| Best for | Database data, app state | Dev code, host configs | Secrets, scratch space |
Named Volumes
Named volumes are the recommended approach for persistent data.
Creating and Using
# Create a named volume
docker volume create pgdata
# Use it with a container
docker run -d \
--name db \
-v pgdata:/var/lib/postgresql/data \
postgres:16
Auto-Creation
If a named volume does not exist, Docker creates it automatically:
# pgdata2 is created automatically
docker run -d -v pgdata2:/var/lib/postgresql/data postgres:16
Volume CRUD Operations
# Create
docker volume create mydata
# List all volumes
docker volume ls
# Inspect a volume (shows mount point, driver, etc.)
docker volume inspect mydata
# Remove a specific volume
docker volume rm mydata
# Remove all unused volumes
docker volume prune
Inspecting Volume Details
docker volume inspect pgdata
Output:
[
{
"CreatedAt": "2024-01-15T10:30:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
"Name": "pgdata",
"Options": {},
"Scope": "local"
}
]
docker volume prune removes all volumes not attached to a running container. Stopped containers' volumes are also removed. Always double-check before running this command.
Bind Mounts
Bind mounts map a specific host directory into the container.
Basic Usage
# Mount current directory into /app
docker run -d \
--name dev \
-v "$(pwd)":/app \
-w /app \
node:20-alpine npm run dev
Read-Only Bind Mounts
# Mount config as read-only
docker run -d \
-v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:alpine
The :ro suffix prevents the container from modifying the host file.
Common Bind Mount Patterns
| Pattern | Example | Use Case |
|---|---|---|
| Source code mount | -v "$(pwd)":/app | Development hot-reload |
| Config file mount | -v ./nginx.conf:/etc/nginx/nginx.conf:ro | Custom configuration |
| Log directory | -v /var/log/myapp:/var/log/app | Centralized logging |
| Socket mount | -v /var/run/docker.sock:/var/run/docker.sock | Docker-in-Docker tools |
Mounting the Docker socket (docker.sock) gives the container full control over the Docker daemon. Only do this for trusted tools like Portainer or Traefik.
tmpfs Mounts
tmpfs mounts store data in the host's memory (RAM). Data is never written to disk and is lost when the container stops.
docker run -d \
--name api \
--tmpfs /tmp:size=100m \
my-api:1.0.0
When to Use tmpfs
| Scenario | Why tmpfs? |
|---|---|
| Secrets / tokens | Never touches disk -- more secure |
| Scratch space for processing | Fast reads/writes, auto-cleaned |
| Temporary session data | No persistence needed |
Volumes in Docker Compose
Named Volumes
services:
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
api:
image: my-api:1.0.0
volumes:
- uploads:/app/uploads
volumes:
pgdata:
uploads:
The top-level volumes: section declares named volumes. Compose creates them automatically.
Bind Mounts
services:
api:
image: my-api:1.0.0
volumes:
- ./src:/app/src # Relative path bind mount
- ./config:/app/config:ro # Read-only
tmpfs
services:
api:
image: my-api:1.0.0
tmpfs:
- /tmp:size=100m
Sharing Volumes Between Services
services:
writer:
image: my-writer:1.0.0
volumes:
- shared-data:/data
reader:
image: my-reader:1.0.0
volumes:
- shared-data:/data:ro
volumes:
shared-data:
Long-Form --mount Syntax
The --mount flag is more explicit than -v and is easier to read for complex configurations:
# Named volume
docker run -d \
--mount type=volume,source=pgdata,target=/var/lib/postgresql/data \
postgres:16
# Bind mount (read-only)
docker run -d \
--mount type=bind,source="$(pwd)"/config,target=/app/config,readonly \
my-api:1.0.0
# tmpfs
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=104857600 \
my-api:1.0.0
-v vs --mount Comparison
| Feature | -v | --mount |
|---|---|---|
| Auto-creates volume | ✅ Yes | ✅ Yes |
| Auto-creates bind host path | ✅ Yes (can mask errors) | ❌ Errors if path missing |
| Readability | Short but ambiguous | Verbose but clear |
| Recommended for | Quick usage, scripts | Production, Compose files |
For production use, prefer --mount because it fails explicitly when a host path is missing, rather than silently creating an empty directory.
Checking What's Mounted
# List mounts for a container
docker inspect -f '{{json .Mounts}}' my-container | python3 -m json.tool
# Quick view of all volumes used by running containers
docker ps --format '{{.Names}}' | xargs -I{} docker inspect -f '{{.Name}}: {{range .Mounts}}{{.Type}}:{{.Source}}->{{.Destination}} {{end}}' {}
Key Takeaways
- Named volumes are the recommended storage for persistent data -- Docker manages them and they are portable.
- Bind mounts map host directories -- ideal for development and config files, but path-dependent.
- tmpfs mounts live in RAM -- use for secrets and scratch data that should never touch disk.
- Use
:rosuffix to mount volumes read-only where the container should not modify data. docker volume pruneis dangerous -- verify what is unused before running it.
What's Next
- Continue to Data Persistence Strategies to learn which storage type to choose for each use case.