.NETEasy
Docker volumes vs bind mounts — when to use which
Both persist data outside the container's writable layer. They differ in who manages the storage and how portable it is.
| Volume | Bind mount | |
|---|---|---|
| Location | Docker-managed (/var/lib/docker/volumes/...) | Any host path you point to |
| Portable across hosts | yes (with volume drivers) | no (host-specific path) |
Backup with docker CLI | yes | no |
| Best on Mac/Windows | yes (fast) | no (slow, filesystem translation) |
| Use cases | Database files, prod data | Dev source-code mounts |
Volume — recommended for production data
docker volume create pgdata
docker run -d --name pg \
-v pgdata:/var/lib/postgresql/data \
postgres:16
In Compose:
services:
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Bind mount — recommended for dev hot-reload
services:
api:
build: .
volumes:
- ./src:/app/src # host source code into container
- /app/node_modules # anonymous volume — protect installed deps
Why never bind-mount production DB data
- Path drift across hosts breaks deploys.
- Filesystem semantics differ (case sensitivity, permissions).
- On Mac/Windows the gVisor / WSL filesystem layer is slow enough to noticeably slow Postgres / Mongo.
tmpfs — the third option
In-memory, never written to disk:
docker run --tmpfs /scratch:size=512m my-image
Useful for build caches and temporary processing where data loss on container restart is acceptable.
Production checklist
- Name your volumes; anonymous volumes (
-v /data) leak ondocker rm. - Back up with
docker run --rm -v pgdata:/data -v $PWD:/backup busybox tar czf /backup/pg.tgz -C /data . - For Kubernetes, volumes become PVs/PVCs; bind mounts become
hostPath(avoid in production).