Docker Compose¶
Multi-container Docker orchestration tool. Define entire application stacks in YAML. Manages containers, networks, volumes together. Development environments made easy. Simpler than Kubernetes for local/small deployments.
2026 Update
Compose V2 is now docker compose (not docker-compose). Better integration with Docker CLI. Watch mode for live reloading. Profiles for environment-specific services. GPU support for ML workloads.
Quick Hits¶
# New syntax (Compose V2, recommended)
docker compose up # Start all services # (1)!
docker compose up -d # Start in background (detached)
docker compose down # Stop and remove containers
docker compose down -v # Also remove volumes
# Build and start
docker compose up --build # Rebuild images before starting
docker compose build # Build images only (no start)
docker compose build --no-cache # Force rebuild from scratch
# Service management
docker compose start # Start existing containers
docker compose stop # Stop containers (don't remove)
docker compose restart # Restart all services
docker compose restart web # Restart specific service
# Logs and monitoring
docker compose logs # View all logs
docker compose logs -f web # Follow logs for specific service # (2)!
docker compose ps # List running services
docker compose top # Display running processes
# Execute commands
docker compose exec web bash # Shell into running service # (3)!
docker compose run web npm test # Run one-off command
docker compose run --rm web npm test # Run and remove after
# Scaling services
docker compose up -d --scale web=3 # Run 3 instances of web service # (4)!
# Profiles (environment-specific)
docker compose --profile dev up # Start dev-profile services only
docker compose --profile prod up
# Watch mode (live reload, V2.22+)
docker compose watch # Auto-rebuild on file changes # (5)!
- Compose V2 syntax:
docker compose(space), notdocker-compose(hyphen) -ffollows logs in real-time (liketail -f)- Most common command for debugging running containers
- Load balancing requires service config without host port mapping
- Watch mode rebuilds containers when source files change
Real talk:
- Compose V2 is faster and better integrated with Docker
- Perfect for local development, not for production at scale
docker-compose.ymldefines entire application stack- Networks created automatically (services can reference by name)
- Volumes persist data across container restarts
# docker-compose.yml (basic web app)
version: '3.8' # (1)!
services:
web:
build:
context: ./app
dockerfile: Dockerfile
ports:
- "3000:3000" # (2)!
environment:
NODE_ENV: development
DATABASE_URL: postgres://db:5432/myapp # (3)!
depends_on:
- db
- redis
volumes:
- ./app:/app # (4)!
- /app/node_modules # (5)!
networks:
- backend
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data # (6)!
networks:
- backend
redis:
image: redis:7-alpine
networks:
- backend
volumes:
postgres_data: # (7)!
networks:
backend: # (8)!
- Version 3.8 supports most features, 3.9+ for newer syntax
host:containerport mapping, expose container port 3000 to host 3000- Services reference each other by service name (DNS built-in)
- Bind mount for live code reloading (changes reflect immediately)
- Anonymous volume prevents overwriting node_modules from host
- Named volume for persistent database storage
- Named volumes defined at top level, persist across
down - Custom network isolates services, auto DNS resolution
# docker-compose.override.yml (development overrides)
# Automatically merged with docker-compose.yml
version: '3.8'
services:
web:
build:
target: development # (1)!
environment:
DEBUG: "true"
volumes:
- ./app:/app:cached # (2)!
command: npm run dev # (3)!
db:
ports:
- "5432:5432" # (4)!
- Multi-stage Dockerfile target for development build
:cachedimproves macOS volume performance- Override default command with dev server (hot reload)
- Expose DB port for local database clients
# docker-compose.prod.yml (production config)
# Use with: docker compose -f docker-compose.yml -f docker-compose.prod.yml up
version: '3.8'
services:
web:
build:
target: production
restart: unless-stopped # (1)!
environment:
NODE_ENV: production
deploy:
replicas: 3 # (2)!
resources:
limits:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3" # (3)!
- Auto-restart on failure, but not if manually stopped
- Deploy section for Swarm mode (not used in standalone Compose)
- Log rotation prevents disk fill-up
# Profiles for conditional services
version: '3.8'
services:
web:
image: myapp:latest
# Always starts (no profile)
debug:
image: myapp:latest
profiles: ["dev"] # (1)!
command: npm run debug
ports:
- "9229:9229" # Node.js debugger
monitoring:
image: prom/prometheus
profiles: ["monitoring"] # (2)!
ports:
- "9090:9090"
- Start with:
docker compose --profile dev up - Multiple profiles can be active:
--profile dev --profile monitoring
Why this works:
- Single YAML file defines entire stack (reproducible environments)
- Override files customize for different environments (dev/prod)
- Networks provide automatic DNS between services
- Volumes persist data, bind mounts enable live reloading
depends_onensures startup order (DB before app)
Best Practices
- Compose V2 syntax - Use
docker composenotdocker-compose - Environment files - Store secrets in
.env(add to .gitignore) - Named volumes - Persist data across container recreation
- Health checks - Add health checks for reliable startup order
- Override files - Use
docker-compose.override.ymlfor local dev - Profiles - Group services by environment (dev, test, prod)
- Resource limits - Set memory/CPU limits in production
Security
- Secrets in .env - Never commit
.envfiles with credentials - Use secrets - Docker secrets for sensitive data (Swarm mode)
- Read-only filesystems - Add
read_only: truewhere possible - Drop capabilities - Use
cap_dropto reduce attack surface - Non-root users - Run containers as non-root (USER in Dockerfile)
Performance
- Build cache - Layer Dockerfile properly for faster rebuilds
- Volume caching - Use
:cachedflag on macOS for better I/O - Prune regularly -
docker system pruneremoves unused resources - Multi-stage builds - Smaller production images
- Parallel builds - Compose builds multiple services in parallel
Gotchas
- Volume ownership - Container user must match host user for writes
- Port conflicts - Check if host ports already in use (change mapping)
- depends_on - Only waits for start, not readiness (use health checks)
- Named volumes location - Find with
docker volume inspect <volume> - Network isolation - Services on different networks can't communicate
- Anonymous volumes - Not cleaned by
down -v(usedocker volume prune) - macOS performance - Bind mounts slower than Linux (use
:cached)
Learning Resources¶
Official Docs¶
- Docker Compose Documentation - Complete reference
- Compose File Reference - YAML syntax
- Compose CLI Reference - All commands
Key Features¶
- Multi-container apps - Define entire stack in single YAML file
- Service dependencies - Control startup order with
depends_on - Networks - Automatic DNS between services
- Volumes - Persistent data storage
- Environment variables -
.envfile support - Profiles - Conditional service activation
- Watch mode - Auto-rebuild on file changes
Related Tools¶
- Docker Swarm - Native clustering (Compose compatible)
- Kubernetes - Production-grade orchestration
- Portainer - Web UI for Docker/Compose
- Kompose - Convert Compose to Kubernetes
Last Updated: 2026-02-02 | Vibe Check: Local Dev Essential - Perfect for development environments. Simple, fast, reproducible. Not for production at scale (use Kubernetes). Compose V2 is much better than V1.
Tags: docker-compose, containers, orchestration, development, docker