Docker Compose Guide: Syntax, Examples, and Common Patterns
Learn Docker Compose file syntax field by field. Covers services, networks, volumes, environment variables, health checks, and real-world multi-container patterns.
Try the free online tool mentioned in this guide:Docker Compose Generator
What is Docker Compose?
Docker Compose is a tool for defining and running multi-container applications from a single YAML file (docker-compose.yml or compose.yml). Instead of running multiple docker run commands with ports, volumes, networks, and environment variables, you declare all services in one file and start everything with docker compose up.
Compose is the standard for local development environments: spin up a web app, database, cache, and message broker with one command, and tear them all down with one command.
Basic docker-compose.yml structure
A Compose file has four top-level keys: services, networks, volumes, and configs. The most used is services.
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./static:/usr/share/nginx/html:ro
depends_on:
- api
api:
build: ./api # build from local Dockerfile
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db_data:Services: the core building block
Each key under services is a container definition. Key fields:
image: Docker Hub image name and tag.build: path to a directory with a Dockerfile, or a build config object.ports: host:container port mapping."8080:80"exposes container port 80 on host port 8080.environment: env vars as a list (- KEY=value) or map (KEY: value).volumes: bind mounts (./local:container) or named volumes.depends_on: start order. Withcondition: service_healthy, waits for the healthcheck.restart:no(default),always,on-failure,unless-stopped.
Environment variables and .env files
Compose automatically reads a .env file in the same directory and substitutes ${VARIABLE} references in the Compose file. Never hard-code secrets in docker-compose.yml committed to git.
# .env file (never commit to git)
POSTGRES_PASSWORD=supersecret
API_SECRET_KEY=myapikey
# docker-compose.yml references
services:
db:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
api:
environment:
SECRET_KEY: ${API_SECRET_KEY}Networks: service-to-service communication
By default, Compose creates a single default network and all services join it. Services reach each other by service name — api can connect to db using the hostname db.
For isolation, define custom networks. A service can join multiple networks.
services:
web:
networks: [frontend]
api:
networks: [frontend, backend]
db:
networks: [backend]
networks:
frontend:
backend:
internal: true # not reachable from hostCommon real-world patterns
Web + Database: nginx/Caddy as reverse proxy, Node/Python/Go API, PostgreSQL or MySQL. The API uses the DB service name as hostname.
Web + Cache: Same as above plus Redis as the cache service. The API connects to redis:6379.
Full stack: Frontend (React/Next.js), backend API, database, Redis, background worker (Celery/BullMQ) — all defined as separate services with shared networks and a volume for the database.
Overrides: Use docker-compose.override.yml for local dev customizations (bind mounts, debug ports) without modifying the base file.
Essential Compose commands
# Start all services (detached)
docker compose up -d
# Start and rebuild images
docker compose up -d --build
# Stop and remove containers (keep volumes)
docker compose down
# Stop and remove containers + volumes
docker compose down -v
# View logs (follow)
docker compose logs -f api
# Run a one-off command in a service container
docker compose exec api sh
# Scale a service to 3 replicas
docker compose up -d --scale worker=3Frequently asked questions
What is the difference between docker-compose and docker compose?
docker-compose (with a hyphen) is the older standalone Python binary (Compose v1). docker compose (space) is the newer Go plugin bundled with Docker Desktop and Docker Engine 20.10+ (Compose v2). Compose v2 is the current standard; v1 is deprecated.
How do I make one service wait for another to be ready?
Use depends_on with condition: service_healthy, and add a healthcheck to the dependency. Without a healthcheck, depends_on only waits for the container to start, not for the service inside to be ready.
Should I use Docker Compose in production?
Compose is designed for local development and single-host deployments. For multi-host production workloads, use Kubernetes, Docker Swarm, or a managed container service (ECS, Cloud Run). Compose is fine for small self-hosted apps on a single server.
What is the difference between volumes and bind mounts in Compose?
Named volumes (db_data:) are managed by Docker and persist data between container restarts independent of host paths. Bind mounts (./local:/container) sync a host directory into the container — used for live code reloading in development.

