Skip to content

How to Mount Volumes in Docker Compose

DodaTech 2 min read

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 :ro to volumes the container should not modify.
  • Use <a href="/devops/docker-compose/">docker compose</a> down -v carefully as it deletes named volumes.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro