Docker Compose File Reference
Docker Compose defines multi-container applications in a single YAML file. Instead of running multiple docker run commands with complex flags, you declare your entire stack — web servers, databases, caches, workers — in compose.yaml and bring it up with docker compose up.
This reference covers the most commonly used Compose directives with practical examples.
Basic Structure
services:
web:
image: nginx:alpine
ports:
- "8080:80"
api:
build: ./api
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
A Compose file has three top-level keys: services (required), volumes (optional), and networks (optional).
Services
Image vs Build
services:
# Use a pre-built image
redis:
image: redis:7-alpine
# Build from a Dockerfile
api:
build:
context: ./api
dockerfile: Dockerfile
args:
NODE_ENV: production
Ports
ports:
- "8080:80" # host:container
- "3000:3000" # same port
- "127.0.0.1:9090:9090" # bind to localhost only
Use expose instead of ports for container-to-container communication without host binding:
expose:
- "6379"
Environment Variables
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
NODE_ENV: production
# Or from a file
env_file:
- .env
Volumes
volumes:
- ./src:/app/src # bind mount (host path)
- node_modules:/app/node_modules # named volume
- /app/dist # anonymous volume
Named volumes persist data across container restarts and recreations:
volumes:
pgdata:
driver: local
Health Checks
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Dependencies
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
Using condition: service_healthy waits for the dependency's health check to pass before starting.
Restart Policy
restart: unless-stopped # restart on failure and on daemon restart, but not if manually stopped
# Other options: "no", "always", "on-failure"
Resource Limits
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
cpus: "0.25"
memory: 256M
Networks
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
Services on the same network can reach each other by service name. Separate networks isolate traffic.
Common Patterns
Web App + Database + Cache
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
REDIS_URL: redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
volumes:
pgdata:
Development vs Production
Use compose.override.yaml for development-specific settings (auto-loaded by Docker Compose):
# compose.yaml (base)
services:
api:
image: myapp:latest
# compose.override.yaml (development)
services:
api:
build: .
volumes:
- ./src:/app/src
environment:
DEBUG: "true"
For production, use a separate file: docker compose -f compose.yaml -f compose.prod.yaml up
Common Mistakes
- Using
latesttag in production —image: postgres:latestcan change at any time. Pin specific versions:postgres:16.2-alpine. - Storing secrets in compose.yaml — environment variables in the file are visible in version control. Use Docker secrets or external secret management.
- Not using health checks with depends_on —
depends_onwithoutcondition: service_healthyonly waits for the container to start, not for the service to be ready. - Bind mounts overwriting node_modules — mounting
./:/appoverwrites the container'snode_modules. Use a named volume fornode_modules. - Not declaring volumes — data in containers is ephemeral. If the container is recreated, any data not in a volume is lost.
Generate Templates
StackCache Docker & Kubernetes Templates generates validated Dockerfile, Compose, and Kubernetes YAML starting points for common stacks — all locally in your browser.
Try it yourself
Open the tool mentioned in this guide — it runs locally in your browser, no account needed.
Open tool