Learn Docker data persistence with a practical 5-minute lab comparing Docker Volumes and Bind Mounts.
Docker Data Persistence: Volumes vs Bind Mounts π§ͺ
By default, Docker containers are ephemeral. If a container stops or gets deleted, any data created inside it vanishes forever.
To prevent data loss, Docker provides two primary mechanisms for data persistence: Docker Volumes and Bind Mounts.
In this practical guide, we will walk through a 5-minute hands-on lab so you can test both approaches directly on your machine.
π Quick Comparison Matrix
| Feature | Docker Volumes (VolΓΊmenes) | Bind Mounts |
|---|---|---|
| Managed By | Docker Engine (/var/lib/docker/volumes/) |
User / Host OS |
| Path on Host | Managed automatically by Docker | Explicit path (e.g., /home/user/app) |
| Best For | Production, Databases, Persistent Storage | Local Development, Live Code Reloading |
| Portability | High (Easy to backup, restore, migrate) | Low (Tied to specific host folder structure) |
| CLI Example | -v my_volume:/app |
-v /host/path:/app |
π§ͺ Hands-on Lab: Try It Yourself
Follow these step-by-step exercises in your terminal.
π Part 1: Docker Volumes (Best for Production & Databases)
Docker Volumes are completely managed by Docker and isolated from the core host file system.
Step 1: Create a managed volume
docker volume create my_volume
Verify that the volume was created:
docker volume ls
Step 2: Start a container with the volume attached
docker run -d --name app_volume -v my_volume:/app nginx
Step 3: Write data inside the container
docker exec app_volume bash -c "echo 'Persistent data from Volume' > /app/data.txt"
Verify the file exists inside:
docker exec app_volume cat /app/data.txt
Step 4: Simulate a crash / Destroy the container
docker rm -f app_volume
Step 5: Attach the same volume to a NEW container
docker run -d --name app_volume_new -v my_volume:/app nginx
Step 6: Verify data persistence
docker exec app_volume_new cat /app/data.txt
Result: You will see
Persistent data from Volume. The data survived the total destruction of the original container!
Cleanup Part 1:
docker rm -f app_volume_new
docker volume rm my_volume
π Part 2: Bind Mounts (Best for Local Development)
Bind Mounts directly link a folder on your host machine to a directory inside the container.
Step 1: Create a local directory on your host machine
mkdir -p ~/docker_lab/html
echo "<h1>Hello from Local Host (V1)</h1>" > ~/docker_lab/html/index.html
Step 2: Start an Nginx container using the bind mount
docker run -d --name web_server -v ~/docker_lab/html:/usr/share/nginx/html -p 8080:80 nginx
Step 3: Test access in your browser or terminal
curl http://localhost:8080
Output:
<h1>Hello from Local Host (V1)</h1>
Step 4: Edit the file locally on your host machine (no container restart!)
echo "<h1>Live update reflected instantly! (V2)</h1>" > ~/docker_lab/html/index.html
Step 5: Verify immediate change
curl http://localhost:8080
Output:
<h1>Live update reflected instantly! (V2)</h1>
Cleanup Part 2:
docker rm -f web_server
rm -rf ~/docker_lab
π‘ Summary & Takeaways / Resumen
- Use Docker Volumes when you need secure, isolated, and high-performance storage for databases (e.g., PostgreSQL, MySQL, MongoDB) or production services.
- Use Bind Mounts when developing code locally so your IDE edits immediately reflect inside the container without rebuilding images.
π¬ Discussion
Which persistence method do you use more in your daily workflow? Have you ever lost data due to container recreation? Let's discuss in the comments below! π
#docker #devops #backend #learning
Top comments (2)
The destroy-the-container-and-reattach exercise is exactly the demo that makes persistence click, and the table matches how I ended up splitting usage in practice: named volumes for anything that must survive, bind mounts only where I want live-edit from the host.
A few gotchas I'd add if you extend it. First-use behavior differs in a way that surprises people: a named volume initialized over a non-empty image directory copies the image content in, while a bind mount shadows it β mount an empty host dir over
/appand your app files "disappear". That asymmetry explains most of the "my files are gone" threads I've seen. Second, on a root-managed box, defaulting to:roon bind mounts that don't need writes has saved me more than once β an agent or a misconfigured app happily writing into a host path is a bad afternoon. Anddocker volume rmrefusing while a stopped container still references the volume is the classic cleanup trap:docker ps -a --filter volume=<name>before deleting, ordocker system prune --volumesdiscipline.Did you deliberately skip compose top-level
volumes:anddocker cp, or is that a part two? Compose named volumes shift the mental model slightly β the lifecycle gets tied to the project instead of the engine.Thatβs fantastic feedback! Thanks for taking the time to write such a thoughtful and value-packed comment.
You nailed the exact pain points that stump most people when moving beyond the basics:
/app" gotcha is indeed responsible for 90% of the initial panic posts on forums. It's one of those things you have to experience once to never forget.:ro): Excellent point on security. Defaulting to:rofor bind mounts when write access isn't required is a top-tier safety practice.docker volume rmcomplaining about stopped containers is a classic rite of passage!Regarding Docker Compose (
volumes:) anddocker cp: yes, that was a deliberate choice! I wanted to keep this initial guide strictly focused on CLI fundamentals and the core mental model without overwhelming beginners.Compose introduces project-level lifecycle management that definitely deserves its own dedicated breakdown. That will be Part 2 of this series!
Thanks again for adding so much depth to the post! π