CoursesDocker for beginnersData, networking & Compose

Persisting data: volumes & bind mounts

Keep data when a container is gone.

Beginner12 min · lesson 12 of 16
In plain terms
A container’s own storage is like a hotel room — housekeeping wipes it the moment you check out. A volume is the storage locker down the hall that stays yours between visits. Keep anything you care about in the locker, not the room.

A container’s writable layer lives and dies with the container: remove the container and everything it wrote is gone. That is exactly what you want for a stateless web server, and exactly what you do not want for a database. To keep data around, you store it outside the container’s layer, in a volume or a bind mount that Docker attaches at a path inside the container.

There are two mechanisms. A named volume is storage Docker creates and manages for you, living in Docker’s own area on disk — the right choice for real data like a database. A bind mount maps a specific directory on your host into the container — the right choice for development, because you can edit source on your machine and the container sees the change immediately.

terminal
# named volume: Docker manages it, survives container removal
$ docker volume create pgdata
$ docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16
# bind mount: a host directory, great for live-editing code in dev
$ docker run -d -v "$(pwd)/src":/app/src myapp:1.0

Which one, when

Reach for named volumes for anything that is real data you want Docker to own and keep portable — databases, uploads, caches that should survive a restart. Reach for bind mounts when you specifically want the host and container to share a directory, overwhelmingly during development for live code reload. There is also tmpfs, an in-memory mount that vanishes on stop, useful for scratch space and secrets you do not want written to disk.

terminal
$ docker volume ls # list volumes
$ docker volume inspect pgdata # where it lives, when created
$ docker run --rm -v pgdata:/data alpine ls /data # peek inside a volume
Remove the container, keep the volume — on purpose
docker rm deletes a container and its writable layer but leaves named volumes intact, which is what protects your database from a careless cleanup. The flip side: anonymous volumes (created when an image declares a VOLUME and you do not name one) accumulate silently. docker volume prune clears the unused ones once you are sure you do not need them.