How to Mount Volumes in Docker Compose
In this tutorial, you'll learn about How to Mount Volumes in Docker Compose. We cover key concepts, practical examples, and best practices.
The Problem
Changes to your source code are not reflected inside the Docker container, or database data disappears after <a href="/devops/docker-compose/">docker compose</a> down. Without volume mounts, each container starts with a fresh filesystem and data is lost when the container stops.
Quick Fix
Step 1: Use a bind mount for live code reload
Mount your local source directory into the container:
services:
app:
image: node:18-alpine
working_dir: /app
volumes:
- ./src:/app/src
- ./package.json:/app/package.json
Now any file change on your host is immediately visible inside the container.
Step 2: Use a named volume for persistent data
Define and use a named volume for database storage:
services:
db:
image: postgres:15
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
The volume persists across container restarts and <a href="/devops/docker-compose/">docker compose</a> down but not <a href="/devops/docker-compose/">docker compose</a> down -v.
Step 3: Use an anonymous volume
Let Docker manage the volume lifecycle:
services:
db:
image: postgres:15
volumes:
- /var/lib/postgresql/data
Anonymous volumes are removed with <a href="/devops/docker-compose/">docker compose</a> down -v.
Step 4: Set read-only volumes
Prevent the container from writing to a mounted directory:
services:
app:
image: my-app:latest
volumes:
- ./config:/app/config:ro
Step 5: Verify volumes are mounted
Check what volumes a running container is using:
docker inspect app_container | grep -A 10 Mounts
"Mounts": [
{
"Type": "bind",
"Source": "/home/user/project/src",
"Destination": "/app/src",
"Mode": "rw",
"RW": true
}
]
Alternative Solutions
Use tmpfs for temporary files
Mount temporary storage in memory for speed:
tmpfs:
- /tmp
Use external volumes for shared data
Reference volumes created outside docker-compose:
volumes:
external_volume:
external: true
Common Mistakes to Avoid
Using bind mounts for production data. Bind mounts depend on the host filesystem structure. Use named volumes for portability across environments.
Not setting :ro for config files. Configuration files mounted into a container should be read-only to prevent the container from modifying them.
Forgetting that volumes persist after down. <a href="/devops/docker-compose/">docker compose</a> down does not remove named volumes. Use <a href="/devops/docker-compose/">docker compose</a> down -v to clean up.
Pro Tips
Use named volumes with labels for organization. Add labels to volumes for easier cleanup: volumes: pgdata: labels: { "project": "myapp" }.
Use docker volume prune --filter to clean selectively. Remove volumes by label or age: docker volume prune --filter "label=project=myapp".
Use tmpfs for cache directories. Avoid disk writes by mounting cache directories as tmpfs: tmpfs: /var/www/html/cache.
Use docker compose cp to inspect volume contents. Copy files from a volume to your host to inspect data: <a href="/devops/docker-compose/">docker compose</a> cp service-name:/path/to/data ./backup/.
Use driver_opts for NFS or SMB volume mounts. Named volumes support driver_opts for type, device, and options: driver_opts: { type: 'nfs', o: 'addr=192.168.1.1', device: ':/path' }.
Prevention
- Use bind mounts for development and named volumes for production data.
- Add
:roto volumes the container should not modify. - Use
<a href="/devops/docker-compose/">docker compose</a> down -vcarefully as it deletes named volumes.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro