Docker Volumes vs Bind Mounts: Where Your Data Actually Lives
Containers are meant to be thrown away. Your database, uploads, and certificates are not. The three ways Docker stores data — the container layer, named volumes, and bind mounts — what survives what, the command that silently deletes your database, and how to back a volume up.
The whole point of a container is that it's disposable. You rebuild it, replace it, and run a fresh copy whenever you like. That's great for code and terrible for data — and the number one Docker surprise is discovering that a database, a folder of uploads, or a set of certificates was living somewhere disposable.
Docker gives you three places to put data. Knowing which is which, and what survives what, prevents nearly every "where did my data go?" moment.
Place 1: the container's own filesystem
Anything a container writes to its own filesystem goes into a thin, writable layer on top of the image. It survives stopping and restarting the container. It does not survive the container being removed — and containers are removed all the time: docker rm, docker run --rm, docker compose down, and every time you rebuild and recreate.
Use it for: nothing you'd miss. Temporary files, caches.
If a Postgres container stores its data here, the database is gone the next time you recreate the container.
Place 2: named volumes
A volume is storage that Docker manages separately from any container. You mount it into a container at a path, and the data lives in the volume, not the container:
docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:17
Or in Compose:
services:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Remove and recreate the container as often as you like; mount the same volume and the data is still there.
Use it for: databases, and any data that belongs to the application rather than to you — uploads, certificate stores, search indexes.
Why volumes rather than a folder you choose? Docker handles permissions and location for you, they perform well on every platform (including Docker Desktop on Mac and Windows), and they're easy to list, inspect, and back up with Docker's own commands.
Place 3: bind mounts
A bind mount maps a specific folder on the host into the container:
docker run -v "$(pwd)":/app -w /app node:22 npm test
The container sees the host's folder directly. Changes on either side appear on the other immediately.
Use it for: development — mounting your source code so edits on your machine are seen instantly by the container. Also for handing specific configuration files to a container.
Watch for:
- Permissions. The container's process writes files as its own user ID, which may not match yours. You end up with files on your machine owned by root, or a container that can't write to the folder. Running the container as your user ID (
--user) usually fixes it. - Performance on Mac and Windows. Bind mounts cross from the host into Docker's VM, which can be much slower for workloads with many small files (
node_modulesis the classic). A common pattern is to bind-mount the source but keepnode_modulesin a named volume. - Exposure. A bind mount gives the container access to that part of your host. Mounting your home directory "for convenience" hands a container your SSH keys and credentials. Mount the narrowest folder you need — and never mount the Docker socket into anything you don't fully trust. (How to Run AI-Generated Code Safely explains why.)
Bonus: tmpfs mounts
A tmpfs mount lives in memory and disappears when the container stops. Good for scratch space and for secrets you don't want written to disk. It counts against the container's memory limit — How Container CPU and Memory Limits Actually Work has the details.
What survives what
| Restart container | Remove & recreate container | docker compose down |
docker compose down -v |
Host disk failure | |
|---|---|---|---|---|---|
| Container filesystem | ✅ | ❌ | ❌ | ❌ | ❌ |
| Named volume | ✅ | ✅ | ✅ | ❌ | ❌ |
| Bind mount | ✅ | ✅ | ✅ | ✅ | ❌ |
Two lessons from that table:
docker compose down -vdeletes your named volumes. The-vmeans "and remove volumes." It's the right command for resetting a development environment and a catastrophic one on a server. Similarly,docker volume pruneremoves volumes not attached to a container — including a database volume whose container happens to be stopped.- Nothing survives the disk dying. A volume is not a backup.
Backing up a volume
For a database, don't copy its files while it's running — you may capture a half-written, inconsistent state. Use the database's own tool:
docker exec my-db pg_dump -U postgres -Fc mydb > mydb.dump
How to Back Up a Postgres Database covers doing this properly, including testing the restore.
For other data — uploads, certificates — a common trick is a throwaway container that mounts the volume and archives it:
docker run --rm \
-v uploads:/data:ro \
-v "$(pwd)":/backup \
alpine tar czf /backup/uploads.tgz -C /data .
Then copy the archive somewhere that isn't the same machine.
A sensible default layout
For a typical app in Docker:
- Application code: baked into the image in production; bind-mounted in development.
- Database data: a named volume. Backed up with the database's dump tool, off the machine.
- User uploads: object storage if possible (Where Should User Uploads Go?); otherwise a named volume, backed up.
- Certificates and proxy state (such as Traefik's
acme.json): a named volume, so certificates aren't re-requested on every restart. (How Automatic SSL Actually Works explains why that matters.) - Caches and temp files: the container's filesystem or tmpfs.
The principle
Decide, for every piece of data, what it would cost to lose — then put it somewhere that matches. Containers are disposable. Anything that isn't should be mounted from outside them, and anything irreplaceable should also be backed up somewhere else entirely.
EasySpawn is built on exactly this split: each workspace is a Docker container you can recreate at any time, with source code, dependencies, and environment variables on mounted persistent storage and databases managed and backed up separately — containers are disposable; project data is not. See how it works or join the waitlist.
Related: Docker vs Linux Users for Multi-Tenant Isolation · What Is a Dev Container? · Docker Compose for Local Development
Keep reading
Zero-Downtime Deploys for a Small App
You don't need Kubernetes to deploy without dropping requests. What actually causes downtime during a deploy — stopping before starting, no health checks, killed requests, and database changes the old code can't handle — and the four practices that fix each one.
What Is Docker? A Beginner's Explanation
Docker packages an app with everything it needs to run, so it works the same on any computer. What containers and images are, how they differ from virtual machines, why hosts and AI tools use them everywhere, and whether you need to learn Docker at all.