One of the most powerful features of Docker is its ability to quickly spin up isolated environments. However, when it comes to persistent data—especially for databases—developers must think carefully. By default, Docker containers are ephemeral: any data written to the container’s filesystem is lost when the container is removed.
In this blog, we’ll explore how to handle persistent storage in Docker, particularly for databases like MySQL, PostgreSQL, MongoDB, and others, using best practices to ensure your data stays intact across container restarts and rebuilds.
Why Persistence Matters
Databases are stateful applications, meaning they store and manage data that must be preserved. Without persistent storage, restarting or deleting a container would result in data loss, which is unacceptable in most production or even development scenarios.
Docker Storage Options
Docker provides two primary mechanisms for persisting data:
1. Volumes
- Managed by Docker.
- Stored outside the container’s filesystem.
- Ideal for databases and persistent storage needs.
2. Bind Mounts
- Links a specific host directory to a container path.
- Useful for development and debugging.
- More tightly coupled to the host filesystem.
Let’s look at each of these in more detail.
Method 1: Using Docker Volumes (Recommended)
Volumes are the most robust and Docker-native way to persist data.
🔧 Example with PostgreSQL:
docker volume create pgdata
docker run -d \
--name my-postgres \
-e POSTGRES_PASSWORD=mysecretpassword \
-v pgdata:/var/lib/postgresql/data \
postgres
pgdata
is a Docker-managed volume./var/lib/postgresql/data
is where PostgreSQL stores its data inside the container.
✅ Benefits:
- Docker manages the lifecycle and location.
- Works well across different environments (e.g., Windows, Linux).
- Can be backed up or migrated easily.
Method 2: Using Bind Mounts
Bind mounts allow you to mount a specific directory from your host system into the container.
🔧 Example with MySQL:
mkdir -p /my/mysql/data
docker run -d \
--name my-mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-v /my/mysql/data:/var/lib/mysql \
mysql
⚠️ Considerations:
- You must manage file permissions and paths manually.
- Paths differ across host OS (Linux vs Windows).
- Not as portable as volumes.
Best Practices for Database Storage in Docker
✅ Use Volumes in Production
Volumes are decoupled from the container lifecycle and can be reused, backed up, or migrated independently.
✅ Separate Data from Application
Never store application data inside the container image. Always mount data separately.
✅ Use docker-compose
for Management
docker-compose.yml
makes it easier to define services with volumes.
Example:
version: "3.8"
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
✅ Backup Your Volumes
Use docker run --rm
or volume-specific tools to backup data:
docker run --rm \
-v pgdata:/data \
-v $(pwd):/backup \
busybox \
tar czvf /backup/pgdata-backup.tar.gz /data
✅ Monitor Volume Usage
Use docker volume ls
and docker volume inspect
to track volumes and troubleshoot.
Common Mistakes to Avoid
- ❌ Writing data to non-mounted directories inside the container.
- ❌ Assuming that restarting a container preserves data (it doesn’t unless volumes are used).
- ❌ Hardcoding host paths with bind mounts across multiple environments.
Summary
Storage Type | Use Case | Portability | Docker Managed | Recommended |
---|---|---|---|---|
Volume | Production, DBs | High | Yes | ✅ |
Bind Mount | Local Dev, Debug | Low | No | ⚠️ |
No Mount | Stateless Apps | N/A | N/A | ❌ |
Conclusion
Handling persistent storage in Docker, especially for databases, is crucial to building stable, production-ready containerized applications. Using Docker volumes ensures that your data is safe even if your containers are not. While bind mounts have their place in development, volumes are the clear choice for long-term reliability and portability.
With the right storage strategy in place, you can enjoy Docker’s flexibility without compromising your data.