Docker’s layered images are great for shipping applications, but by default every change a container makes disapears when the container is removed. To keep that data around we need to look at the three official persistence mechanisms—volumes, bind mounts, and tmpfs mounts—and understand why they exist in the first place.
Why the Union File System Isn’t Enough
Each Docker image is a stack of read-only layers. When you start a container, Docker adds a thin writable layer on top. This stack is called a Union File System. Any file created or modified inside the container lands in that writable layer only. The moment the container is deleted, the writable layer vanishes, taking your changes with it. UnionFS therefore gives you:
- Fast image reuse and distribution
- Isolation between containers
- But zero durability
Volume, Bind Mount, or tmpfs?
| Mechenism | Where the data lives | Lifetime | Typical use-case |
|---|---|---|---|
| Volume | /var/lib/docker/volumes/... |
Survives container removal | Databases, shared caches |
| Bind mount | Any host directory you pick | Survives container & engine removal | Source code, config files |
| tmpfs mount | Host RAM (swap-backed) | Vanishes when container stops | Secrets, short-lived scratch files |
Working with Named Volumes
Create and inspect
docker volume create web_logs
docker volume ls
docker volume inspect web_logs
Attach at run-time
docker run -d \
--name nginx \
-v web_logs:/var/log/nginx \
nginx:alpine
Data written to /var/log/nginx inside the container is now stored in the web_logs volume and remains after the container is removed.
Populate on first use
If the image already contains files in /var/log/nginx, Docker copies them into the newly created volume so the container starts with sensible defaults.
Share between containers
docker run -d --name log_processor --volumes-from nginx alpine tail -f /var/log/nginx/access.log
Backup & restore
# Backup
docker run --rm \
--volumes-from nginx \
-v $(pwd):/backup \
alpine tar czf /backup/web_logs.tgz -C /var/log/nginx .
# Restore
docker run --rm \
-v web_logs:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/web_logs.tgz -C /data
Declarative Volumes in a Dockerfile
FROM alpine:3.19
WORKDIR /app
RUN apk add --no-cache curl
VOLUME ["/uploads", "/cache"]
Building an image with this Dockerfile and running it will automatically create anonymous volumes for /uploads and /cache. You can later give those volumes names or map them to host directories.
Bind Mounts for Development
Bind mounts map any host path into the container. They are ideal when you need to edit source code on the host and see changes immediately inside the container..
docker run --rm -it \
--mount type=bind,src=$(pwd)/src,dst=/var/www/html,readonly \
php:8.3-cli php -S 0..0.0:8000 -t /var/www/html
tmpfs for Ephemeral Secrets
Use --tmpfs when you want files to live only in memory:
docker run --rm -it --tmpfs /run/secrets:rw,size=10m alpine sh
Everything under /run/secrets disappears when the container exits, leaving no trace on disk.
Quick Reference
# Remove unused volumes
docker volume prune
# Upgrade a container while keeping its data
docker stop db
docker rm db
docker run -d --name db -v db_data:/var/lib/postgresql/data postgres:16
By choosing the right storage mechanism you can keep stateful workloads safe, share data between containers, and still enjoy Docker’s lightweight immutability everywhere else.