Containers are disposable by design: delete one and its writable layer - including every file it created - vanishes. That is perfect for stateless web servers and a disaster for databases. This lesson explains how Docker persists data using volumes and bind mounts, and when to choose each.
Try this experiment:
docker run -d --name db postgres:16
# ... the database writes data inside the container ...
docker rm -f db
# all of that data is now gone foreverAny data written to the container filesystem lives in its temporary writable layer. Removing the container removes the data. Persistence requires storing data outside the container, and Docker offers two main mechanisms.
A volume is a piece of storage created and managed by Docker itself, stored in a Docker-controlled area of the host filesystem:
docker volume create pgdata
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16The syntax is -v volume-name:/path/inside/container. Postgres writes to /var/lib/postgresql/data as usual, but those writes land in the pgdata volume. Now the data survives anything that happens to the container:
docker rm -f db
docker run -d --name db2 -v pgdata:/var/lib/postgresql/data postgres:16
# db2 starts with all the previous data intactDocker even creates the volume automatically if it does not exist yet. Manage volumes with:
docker volume ls
docker volume inspect pgdata
docker volume rm pgdata
docker volume prune # remove volumes no container usesA bind mount maps a specific directory on the host into the container. Instead of a volume name, you give an absolute path:
docker run -d -p 8080:80 -v "$(pwd)/site:/usr/share/nginx/html" nginxNow Nginx serves whatever is in your local site folder, and edits on the host appear in the container instantly. Bind mounts shine in development: mount your source code into the container, and your app reloads on every save without rebuilding the image.
docker run -it --rm -v "$(pwd):/app" -w /app node:20 npm run devThere is a third option, --tmpfs, which keeps data in memory only - useful for scratch space and secrets that should never touch disk.
Append :ro to make a mount read-only inside the container - a good habit for configuration:
docker run -d -v "$(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro" nginxA classic trick uses a temporary container to tar a volume to the host:
docker run --rm -v pgdata:/data -v "$(pwd):/backup" ubuntu tar czf /backup/pgdata.tar.gz -C /data .The same pattern in reverse restores it. No downtime tooling required.
:ro for configuration files the container should never modify.docker volume prune cleans up, and a throwaway container can back up any volume.Next up: Docker Networking, where you will connect containers to each other and to the outside world.