Docker Compose
Define multi-container applications with Docker Compose — services, networking, volumes, and environment configuration in a single YAML file.
Compose File Structure
Docker Compose defines multi-container apps in compose.yml (or docker-compose.yml). Each service is a container with its own image, ports, environment, and volumes. Compose handles networking between services automatically.
Services communicate by service name — a web service connects to db:5432, not localhost:5432. Compose creates a dedicated network for the project.
- Use compose.yml (no hyphen) — the modern convention
- depends_on with condition waits for health checks, not just start
- Service names become DNS hostnames within the compose network
services:
web:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
volumes:
pgdata:Compose Commands
docker compose up starts all services. Add -d for detached mode. docker compose down stops and removes containers, networks, and optionally volumes. docker compose logs -f follows service logs.
Use docker compose exec web sh to access a running service. docker compose build rebuilds images. docker compose ps shows service status.
docker compose up -d # Start all services docker compose logs -f web # Follow web logs docker compose exec db psql -U user myapp docker compose down -v # Stop and remove volumes docker compose up --build -d # Rebuild and start
Networking in Compose
Compose creates a default bridge network for the project. All services join this network and resolve each other by name. Expose ports only for services that need external access.
Custom networks enable isolation between service groups. An frontend network for web-facing services and a backend network for databases adds security layers.
services:
web:
networks: [frontend, backend]
api:
networks: [backend]
db:
networks: [backend]
networks:
frontend:
backend:
internal: true # No external accessEnvironment and Profiles
Use env_file to load environment variables per service. Override with .env file in the project root for local development. Profiles activate optional services — a debug profile adds monitoring tools without running them by default.
Multiple compose files merge: docker compose -f compose.yml -f compose.prod.yml up combines base and production overrides.
services:
web:
env_file: .env
profiles: ["default"]
adminer:
image: adminer
ports: ["8080:8080"]
profiles: ["debug"]
# Start with debug profile
# docker compose --profile debug upDevelopment Workflow
Mount source code as volumes for live development. The container runs the app, but code changes on the host reflect immediately. Combine with nodemon or vite dev server for hot reloading.
Use compose watch (Docker Compose v2.22+) for automatic file sync and rebuild on changes — a modern replacement for volume mount development.
services:
web:
build: .
volumes:
- ./src:/app/src
- /app/node_modules # Preserve container node_modules
develop:
watch:
- action: sync
path: ./src
target: /app/src