Compose File Structure
A Compose file (compose.yaml or docker-compose.yml) defines your entire application stack -- services, networks, and volumes -- in a single, version-controlled YAML file. Instead of running multiple docker run commands, you describe what you want and Compose handles the rest.
The Three Top-Level Keys
Every Compose file is built from three sections:
services: # The containers to run
webapp:
image: my-app:1.0.0
ports:
- "80:3000"
environment:
- DB_HOST=database
depends_on:
- database
database:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
volumes: # Named volumes for persistent data
db_data: {}
networks: # Custom networks (optional -- Compose creates a default)
default: {}
flowchart TD
subgraph Compose["compose.yaml"]
LB["Reverse Proxy<br/>(nginx)"]
APP["Web App<br/>(node)"]
DB["Database<br/>(postgres)"]
CACHE["Cache<br/>(redis)"]
LB --> APP
APP --> DB
APP --> CACHE
end
User -->|"Port 80"| LB
style Compose fill:#e3f2fd,stroke:#1565c0
Key Properties Reference
| Property | CLI Equivalent | Example |
|---|---|---|
image | docker run IMAGE | nginx:alpine |
build | docker build | build: ./backend |
ports | -p | "8080:80" |
volumes | -v | ./data:/data |
environment | -e | DEBUG=true |
env_file | --env-file | env_file: .env |
command | Override CMD | npm start |
restart | --restart | unless-stopped |
depends_on | Startup ordering | depends_on: [db] |
networks | --network | networks: [front, back] |
healthcheck | --health-cmd | test: ["CMD", "curl", "-f", "http://localhost"] |
Compose V1 vs V2
| Feature | Compose V1 (Legacy) | Compose V2 (Current) |
|---|---|---|
| Command | docker-compose (hyphen) | docker compose (space) |
| Language | Python | Go (integrated into Docker CLI) |
| Status | Deprecated | Standard |
Always Use V2
Use docker compose (with a space). It is faster, natively integrated, and actively maintained.
Essential Commands
# Start all services in background
docker compose up -d
# View status of all services
docker compose ps
# View logs (follow mode)
docker compose logs -f
# View logs for one service
docker compose logs -f webapp
# Stop and remove containers + networks
docker compose down
# Stop, remove containers, AND delete volumes (full reset)
docker compose down -v
# Rebuild images and restart
docker compose up -d --build
# Validate your compose file (catches syntax errors)
docker compose config
# Pull latest images before starting
docker compose pull
File Naming
Compose looks for these filenames (in order):
compose.yaml(modern standard)compose.ymldocker-compose.yamldocker-compose.yml
Compose also automatically merges compose.override.yaml if it exists -- useful for local development overrides.
Example: Full Stack
services:
proxy:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks: [front, back]
restart: unless-stopped
api:
build: ./api
environment:
DB_HOST: db
REDIS_HOST: cache
networks: [back]
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks: [back]
restart: unless-stopped
cache:
image: redis:7-alpine
networks: [back]
restart: unless-stopped
networks:
front: {}
back: {}
volumes:
pgdata: {}
This defines a complete stack: reverse proxy → API → database + cache, with explicit networks, health checks, and restart policies.
Key Takeaways
- Compose files have three top-level sections:
services,volumes, andnetworks. - Use
docker compose up -dto start anddocker compose downto stop. - Use
docker compose configto validate your file before deploying -- it catches syntax errors and shows the merged result. - Always use Compose V2 (
docker composewith a space). - Define networks explicitly in multi-tier stacks to control which services can communicate.
What's Next
- Continue to Environment Variables and Secrets to learn how to manage configuration safely.