Skip to main content

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

PropertyCLI EquivalentExample
imagedocker run IMAGEnginx:alpine
builddocker buildbuild: ./backend
ports-p"8080:80"
volumes-v./data:/data
environment-eDEBUG=true
env_file--env-fileenv_file: .env
commandOverride CMDnpm start
restart--restartunless-stopped
depends_onStartup orderingdepends_on: [db]
networks--networknetworks: [front, back]
healthcheck--health-cmdtest: ["CMD", "curl", "-f", "http://localhost"]

Compose V1 vs V2

FeatureCompose V1 (Legacy)Compose V2 (Current)
Commanddocker-compose (hyphen)docker compose (space)
LanguagePythonGo (integrated into Docker CLI)
StatusDeprecatedStandard
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):

  1. compose.yaml (modern standard)
  2. compose.yml
  3. docker-compose.yaml
  4. docker-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, and networks.
  • Use docker compose up -d to start and docker compose down to stop.
  • Use docker compose config to validate your file before deploying -- it catches syntax errors and shows the merged result.
  • Always use Compose V2 (docker compose with a space).
  • Define networks explicitly in multi-tier stacks to control which services can communicate.

What's Next