Persisting data: volumes & bind mounts
Keep data when a container is gone.
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.
# 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.
$ 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