Compose File Reference
The Docker Compose file (docker-compose.yml) defines the services, networks, and volumes for your multi-container application. This reference covers the most important configuration options.
File Structure
A Compose file has the following top-level elements:
yaml
# Optional: Compose specification version (not required in modern Compose)
# version: "3.9" # Deprecated in Compose V2
# Service definitions
services:
web:
# ...service configuration
api:
# ...service configuration
# Network definitions
networks:
frontend:
# ...network configuration
# Volume definitions
volumes:
data:
# ...volume configuration
# Secret definitions
secrets:
db-password:
# ...secret configuration
# Config definitions
configs:
app-config:
# ...config configurationServices
Services are the core of a Compose file. Each service defines a container that should be running.
Image Configuration
yaml
services:
# Use a pre-built image
web:
image: nginx:1.25-alpine
# Build from a Dockerfile
api:
build: ./api
# Build with advanced options
app:
build:
context: ./app
dockerfile: Dockerfile.prod
args:
NODE_ENV: production
VERSION: "2.0"
target: production
cache_from:
- myuser/myapp:cache
platforms:
- linux/amd64
- linux/arm64
labels:
com.example.description: "My App"Build Configuration Options
| Option | Description | Example |
|---|---|---|
context | Build context path or URL | ./app, https://github.com/user/repo.git |
dockerfile | Alternate Dockerfile path | Dockerfile.prod |
args | Build-time arguments | NODE_ENV: production |
target | Multi-stage build target | production |
cache_from | Cache sources | myuser/app:cache |
cache_to | Cache destinations | type=registry,ref=cache:latest |
platforms | Target platforms | linux/amd64, linux/arm64 |
labels | Image labels | version: "1.0" |
no_cache | Disable build cache | true |
pull | Always pull base image | true |
Port Mapping
yaml
services:
web:
ports:
# Short syntax
- "80:80" # host:container
- "443:443"
- "8080:80" # Different host port
- "127.0.0.1:8080:80" # Bind to localhost only
- "3000" # Random host port
- "8080-8090:80-90" # Port range
# Long syntax
- target: 80
published: 8080
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcpEnvironment Variables
yaml
services:
api:
# Map syntax
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: "5432"
API_KEY: ${API_KEY} # From shell or .env file
# List syntax
environment:
- NODE_ENV=production
- DB_HOST=db
- API_KEY # Pass through from host
# From file(s)
env_file:
- .env
- .env.local
- path: .env.prod
required: false # Don't fail if missingVolumes
yaml
services:
app:
volumes:
# Named volume
- data:/app/data
# Bind mount (short syntax)
- ./src:/app/src
- ./config:/app/config:ro
# Bind mount (long syntax)
- type: bind
source: ./logs
target: /app/logs
read_only: false
# Named volume (long syntax)
- type: volume
source: data
target: /app/data
volume:
nocopy: true
# tmpfs mount
- type: tmpfs
target: /app/temp
tmpfs:
size: 100000000 # 100 MB
mode: 1777
volumes:
data:
driver: local
driver_opts:
type: none
o: bind
device: /srv/dataDependencies
yaml
services:
web:
depends_on:
# Simple form
- api
- db
api:
depends_on:
# Conditional form (with health checks)
db:
condition: service_healthy
restart: true
redis:
condition: service_started
migrations:
condition: service_completed_successfullyDependency Conditions
| Condition | Description |
|---|---|
service_started | Wait for service to start (default) |
service_healthy | Wait for service health check to pass |
service_completed_successfully | Wait for service to complete with exit code 0 |
Health Checks
yaml
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
start_interval: 5s
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 10s
timeout: 5s
retries: 5
disabled:
healthcheck:
disable: trueRestart Policies
yaml
services:
web:
restart: "no" # Never restart (default)
api:
restart: always # Always restart
worker:
restart: on-failure # Restart on failure only
db:
restart: unless-stopped # Restart unless explicitly stoppedResource Limits
yaml
services:
api:
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
pids: 100
reservations:
cpus: '0.25'
memory: 128MCommand and Entrypoint
yaml
services:
app:
# Override the default command
command: npm run dev
# Shell form
command: "echo hello && npm start"
# Exec form (preferred)
command: ["npm", "run", "dev"]
# Override entrypoint
entrypoint: ["python", "-u"]
command: ["app.py", "--debug"]Logging
yaml
services:
api:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
compress: "true"
silent:
logging:
driver: noneContainer Configuration
yaml
services:
app:
container_name: my-app # Fixed container name
hostname: app-server # Container hostname
domainname: example.com # Domain name
working_dir: /app # Working directory
user: "1000:1000" # Run as user:group
stdin_open: true # Equivalent to -i
tty: true # Equivalent to -t
init: true # Use init process (tini)
read_only: true # Read-only root filesystem
privileged: false # Never use in production
stop_grace_period: 30s # Time before SIGKILL
stop_signal: SIGTERM # Stop signal
platform: linux/amd64 # Target platformSecurity
yaml
services:
app:
security_opt:
- no-new-privileges:true
- seccomp:custom-profile.json
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp
- /var/run
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000Networks
yaml
networks:
# Default network (auto-created)
default:
driver: bridge
# Custom bridge network
frontend:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1
# Internal network (no external access)
backend:
driver: bridge
internal: true
# External network (pre-existing)
existing:
external: true
name: my-pre-existing-network
# Network with labels
labeled:
driver: bridge
labels:
com.example.project: "myapp"Volumes
yaml
volumes:
# Simple named volume
data:
# Volume with driver options
db-data:
driver: local
driver_opts:
type: nfs
o: "addr=192.168.1.100,rw"
device: ":/exports/data"
# External volume
shared-data:
external: true
name: my-shared-volume
# Volume with labels
logs:
labels:
com.example.description: "Application logs"Secrets and Configs
yaml
services:
db:
secrets:
- db_password
- source: db_root_password
target: /run/secrets/root_pw
uid: '103'
gid: '103'
mode: 0440
web:
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
secrets:
db_password:
file: ./secrets/db_password.txt
db_root_password:
environment: DB_ROOT_PASSWORD
configs:
nginx_config:
file: ./nginx/nginx.confVariable Substitution
yaml
services:
web:
image: nginx:${NGINX_VERSION:-1.25}
ports:
- "${WEB_PORT:-80}:80"
db:
image: postgres:${PG_VERSION:?PG_VERSION must be set}
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}| Syntax | Behavior |
|---|---|
${VAR} | Value of VAR (empty if unset) |
${VAR:-default} | Value of VAR, or default if unset/empty |
${VAR-default} | Value of VAR, or default if unset |
${VAR:?error} | Value of VAR, or exit with error if unset/empty |
${VAR?error} | Value of VAR, or exit with error if unset |
Complete Example
yaml
services:
frontend:
build:
context: ./frontend
target: production
ports:
- "80:80"
- "443:443"
depends_on:
api:
condition: service_healthy
networks:
- frontend-net
restart: unless-stopped
api:
build:
context: ./api
args:
NODE_ENV: production
ports:
- "3000:3000"
environment:
- DB_HOST=db
- REDIS_HOST=redis
env_file:
- .env
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend-net
- backend-net
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
db:
image: postgres:16-alpine
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend-net
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
networks:
- backend-net
restart: unless-stopped
networks:
frontend-net:
backend-net:
internal: true
volumes:
db-data:
redis-data:Next Steps
- Compose in Production — Deploy Compose apps to production
- Docker Compose Quick Start — Getting started tutorial
- Compose File Format — Complete specification reference
- Docker Networking Guide — Advanced networking
- Storage Management — Volume management