Your Data's Best Friend in Containerized Applications

Thumbnail for Docker Compose Volumes

Have you ever built a Dockerized backend application that worked flawlessly while you were using it, only to discover that all your data vanished once you shut down your local machine or remote server? That frustrating moment of having to recreate everything makes you wonder: Isn’t there a way to store data permanently? Enter Docker Compose volumes the lifesavers that make your data persistent, shareable, and resilient in a containerized world.
In this five-minute read, I will demystify Docker Compose volumes: what they are, why they are indispensable, and how to use them in your docker-compose.yml file.


Prefer learning through video? Check out my YouTube guide 🎥

Habibi Coding Video - Docker Compose Volumes

What Exactly Are Docker Compose Volumes?

A Docker volume is a way to persist data generated or used by containers. It is a dedicated storage location that lives outside the container’s ephemeral filesystem (temporary filesystem that only exists as long as the container is running). When you use volumes in Docker Compose, you are basically telling Docker: “Take this folder from my computer (or a special storage space managed by Docker) and make it available inside the container at a specific location.” It’s like plugging a USB stick into the container so it can read and write files there.

You will typically use two types of volumes:

  1. Named Volumes: They are managed by Docker, you define them by name, and Docker handles the storage and lifecycle. Ideal for databases or logs.
  2. Bind Mounts: These link a specific file or directory from your host system into the container. Perfect for development, where you want live code changes to reflect instantly inside the container.

Why Do They Matter So Much?

Imagine you building a blog platform with a database container like PostgreSQL or MySQL. Without volumes, all your posts, user data, likes and comments would vanish every time you restart or remove the container. Volumes solve this by enabling:

  • Data Persistence: Volumes ensure your data survives container rebuilds and restarts. Your data lives on the host, not inside a short-lived container.
  • Data Sharing: Multiple services can access the same volume for instance, you want to share data or even files between the web app and a background worker.
  • Improved Performance: For I/O-heavy workloads, volumes can outperform the container's writable layer.
  • Simplified Backups & Migrations: Data on the host is easier to back up and migrate than saving data from inside the Docker container.
  • Development Convenience (Bind Mounts): Easily sync local file changes with a running container no need to rebuild images constantly.

How to Use Them: A Quick Dive into docker-compose.yml

Using volumes in your Compose file is quite straightforward.

Named Volume example for a database

  • We define a named volume called db_data at the top level under volumes:.
  • Inside the db service, we map db_data to PostgreSQL’s data directory (/var/lib/postgresql/data). Now your database data persists even after restarting or removing the container.

Bind Mount example for development

  • The local directory ./app is mounted to /usr/src/app inside the container.
  • Changes you make locally to the app directory are reflected instantly inside the container.

Types of Volumes

  • Named Volumes: Managed by Docker and stored in /var/lib/docker/volumes/.
  • Bind Mounts (Host Path Volumes): Direct mappings of host directories to container paths (for example: ./data:/var/lib/mysql).
  • Anonymous Volumes: Auto-generated volumes without names are temporary and not ideal for persistent data.

Best Practices

  • Use named volumes for storing persistent application data (databases).
  • Avoid host path volumes in production unless absolutely necessary, because they can introduce portability issues.
  • Periodically clean up unused volumes with docker volume prune.

Permission Management Between Host Volumes & Containers

When working with volumes, one common challenge is file and folder permissions. Since a container often runs processes as a specific user (for example: postgres in a PostgreSQL image, ornode in a Node.js image). Those processes need the right permissions to read and write to the mounted volume. On the other hand, the files on your host machine are owned by your local user. If the user IDs don’t match, you may run into issues such as “Permission denied” when your container tries to access the volume. There are a few ways to handle this. You can adjust permissions on the host with chmod or chown. Run the container with a matching user ID (--user flag), or configure your Dockerfile to create a dedicated user inside the container that aligns with your host setup. For development bind mounts usually works fine after a quick chmod 777 on the mounted folder. In production, it is better to adopt a stricter principle of the least privilege approach to avoid security risks.

If your local user has UID 1000 (user id) and GID 1000 (group id), you can run a container so it uses the same user and group as your host system. Files created inside the container will belong to your local user and permission issues are avoided.
Bash example:


In case you are using Docker Compose, you can add a user entry directly in your service definition:

Wrapping Up

Docker Compose volumes are essential for building durable, flexible, and developer-friendly containerized applications. Whether you are persisting database data or hot-reloading your app during development, volumes are a powerful tool that saves both time and resources.

I hope you enjoyed this blog post and feel inspired to make Docker Compose volumes your data’s best friend!

Frequently Asked Questions

Find answers to common questions about Docker Compose volumes

What is a Docker Compose volume?

A Docker Compose volume is a way to store and share data outside of a container’s temporary filesystem. It allows you to persist data even if a container is stopped, restarted, or rebuilt.

Why should I use volumes instead of storing data inside containers?

Containers have ephemeral filesystems, meaning all data is lost once the container is removed. Volumes solve this by keeping the data on the host machine (or in Docker-managed storage), ensuring your data persists across restarts and deployments.

What is the difference between a named volume and a bind mount?

A named volume is managed by Docker and stored in Docker’s internal storage, ideal for production environments and databases. A bind mount maps a specific folder from your host machine into a container, which is especially useful during development to instantly reflect local code changes.

Can multiple containers use the same volume?

Yes. You can attach the same volume to multiple services. This is useful when different containers (for example, a web app and a worker service) need access to the same files or shared data.

How do I clean up unused volumes?

Over time, unused volumes can accumulate and take up space. You can safely remove them with the command docker volume prune, which deletes all volumes not currently used by any container.

Want to buy me a coffee?