Docker Compose Cheat Sheet β€” Complete Reference Guide (2025)

Introduction: What is Docker Compose?

Docker Compose is a powerful tool that allows you to define and run multi-container Docker applications with a single command. Instead of manually running multiple docker run commands for each service, you write a declarative docker-compose.yml configuration file that describes your entire application stack.

Why Use Docker Compose?

Docker Compose is perfect for development, testing, and small production deployments. For large-scale deployments, Kubernetes is recommended.

Installation & Quick Reference

Install Docker Compose (v2+)

Docker Compose v2+ comes bundled with Docker Desktop and Docker Engine on Linux.

Verify Installation

# Check version
docker compose version

# Should output: Docker Compose version 2.x.x

Install on Linux (if not included)

curl -L https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker compose version

docker-compose.yml Structure & YAML Reference

The docker-compose.yml file is the blueprint for your entire application. Here's the complete structure with all available options:

Basic File Structure

version: '3.9'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
    networks:
      - frontend

  api:
    build:
      context: ./app
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DB_HOST=postgres
    depends_on:
      - postgres
    networks:
      - backend

  postgres:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD=secret123
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - backend

volumes:
  db_data:

networks:
  frontend:
  backend:

Complete Service Configuration Reference

Property Type Description Example
image String Docker image to use nginx:latest
build Object/String Build image from Dockerfile ./app or {context: ./app, dockerfile: Dockerfile}
ports Array Expose ports: "host:container" ["8080:80", "5432:5432"]
environment Object/Array Environment variables NODE_ENV: production or array format
volumes Array Mount volumes: "host:container:mode" ["./data:/data", "db_vol:/var/lib/postgresql"]
depends_on Array/Object Service dependencies - postgres or {postgres: {condition: service_healthy}}
restart String Restart policy no, always, on-failure, unless-stopped
command String/Array Override default command python app.py or array format
healthcheck Object Health check configuration {test: ["CMD", "curl", "localhost"], interval: 30s}
networks Array Custom networks to join - frontend, - backend
container_name String Custom container name my_app_web
working_dir String Working directory inside container /app
user String Run as specific user 1000:1000 or "nobody"
cpu_shares Integer CPU resources (relative weight) 1024
mem_limit String Memory limit 512m, 1g

Version Compatibility

Use version 3.9 or higher for most modern use cases:

βœ“ Recommended Versions
  • 3.9: Latest stable, supports all features
  • 3.8: Still widely supported
  • 2.1: Legacy, limited features

Healthcheck Configuration

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

Essential Docker Compose Commands

Command Description Example
docker compose up Start all services defined in compose file docker compose up or docker compose up -d (detached)
docker compose down Stop and remove containers, networks docker compose down or with -v to remove volumes
docker compose ps List running services docker compose ps or docker compose ps -a (all)
docker compose logs View service logs docker compose logs or docker compose logs -f api (follow)
docker compose build Build or rebuild images docker compose build or docker compose build --no-cache
docker compose exec Execute command in running container docker compose exec postgres psql -U postgres
docker compose run Run one-off command in service docker compose run api npm test
docker compose stop Stop running services (keep containers) docker compose stop or docker compose stop api
docker compose start Start stopped services docker compose start or docker compose start postgres
docker compose restart Restart running services docker compose restart or docker compose restart api
docker compose pull Pull latest images from registry docker compose pull
docker compose config Validate and display merged compose config docker compose config
docker compose kill Force stop services docker compose kill or docker compose kill -s SIGKILL
docker compose rm Remove stopped containers docker compose rm or docker compose rm -f (force)

Command Variations & Useful Flags

# Run with specific compose file
docker compose -f docker-compose.prod.yml up -d

# Run in project directory
cd /path/to/project && docker compose up

# Scale specific service
docker compose up --scale api=3

# View logs with timestamps
docker compose logs --timestamps

# Follow logs from specific service
docker compose logs -f postgres

# Rebuild without cache
docker compose build --no-cache api

# Run interactive shell
docker compose exec -it api bash

# Display environment variables in container
docker compose exec api printenv

Common Patterns & Real-World Examples

Pattern 1: Multi-Container Web Application (Nginx + Node.js + PostgreSQL)

version: '3.9'

services:
  nginx:
    image: nginx:latest
    container_name: app_nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - api
    networks:
      - frontend
    restart: unless-stopped

  api:
    build:
      context: ./app
      dockerfile: Dockerfile
    container_name: app_api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=postgres
      - DB_PORT=5432
      - DB_USER=appuser
      - DB_PASSWORD=secure_password
    volumes:
      - ./app:/app
      - /app/node_modules
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - frontend
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  postgres:
    image: postgres:15-alpine
    container_name: app_postgres
    environment:
      - POSTGRES_USER=appuser
      - POSTGRES_PASSWORD=secure_password
      - POSTGRES_DB=appdb
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

networks:
  frontend:
  backend:

Pattern 2: Development vs Production Configuration

docker-compose.yml (base):

version: '3.9'
services:
  api:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=postgres
    volumes:
      - ./app:/app

docker-compose.override.yml (development):

services:
  api:
    environment:
      - NODE_ENV=development
      - DEBUG=*
    command: npm run dev

docker-compose.prod.yml (production):

services:
  api:
    environment:
      - NODE_ENV=production
      - DEBUG=false
    command: npm run start
    restart: always
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M

Usage:

# Development
docker compose up

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Pattern 3: Environment Variable Management with .env

.env file:

# Database
DB_HOST=postgres
DB_USER=appuser
DB_PASSWORD=my_secure_password_here
DB_NAME=production_db

# Application
NODE_ENV=production
APP_PORT=3000
LOG_LEVEL=info

# Redis
REDIS_HOST=redis
REDIS_PORT=6379

docker-compose.yml:

version: '3.9'
services:
  api:
    image: myapp:latest
    environment:
      - DB_HOST=${DB_HOST}
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_NAME=${DB_NAME}
      - NODE_ENV=${NODE_ENV}
      - APP_PORT=${APP_PORT}

Variables in ${VAR} format are automatically replaced from .env file.

Pattern 4: Networking Between Services

version: '3.9'

services:
  frontend:
    image: frontend:latest
    networks:
      - frontend_net

  api:
    image: api:latest
    networks:
      - frontend_net
      - backend_net
    # Frontend can reach API at http://api:3000

  database:
    image: postgres:15
    networks:
      - backend_net
    # API can reach database at postgres://database:5432

networks:
  frontend_net:
    driver: bridge
  backend_net:
    driver: bridge
πŸ’‘ Key Networking Insight

Services communicate using the service name as hostname. For example, a service named postgres is automatically accessible as postgres:5432 to other services on the same network.

Troubleshooting β€” 5 Common Issues & Solutions

Issue 1: "ERROR: Service 'api' failed to build"

Problem

Dockerfile has syntax errors or missing dependencies

Solution:

# View detailed build output
docker compose build --no-cache api

# Check Dockerfile syntax
docker build --dry-run ./app

Issue 2: "Cannot connect to service: Connection refused"

Problem

Services haven't started yet or are on different networks

Solution:

# Verify all services are running
docker compose ps

# Check service logs for startup errors
docker compose logs postgres

# Ensure services are on same network
docker compose exec api ping postgres

# Use depends_on with service_healthy condition
# In docker-compose.yml:
# depends_on:
#   postgres:
#     condition: service_healthy

Issue 3: "Volume mount permission denied"

Problem

Container user doesn't have permissions for mounted directory

Solution:

# Fix permissions on host
chmod 755 /path/to/volume

# Or specify user in docker-compose.yml
user: "1000:1000"

# For database volumes, use proper ownership
chown -R 999:999 ./postgres_data

Issue 4: "Docker Compose hangs or times out"

Problem

Services take too long to become ready, or process is stuck

Solution:

# Increase timeout for depends_on
# docker-compose.yml: start_period in healthcheck

# View service logs in real-time
docker compose logs -f

# Force stop (use cautiously)
docker compose kill

# Clear everything and restart
docker compose down -v
docker compose up --build

Issue 5: "Out of disk space" or "Cannot write to volume"

Problem

Docker volumes consuming too much disk space

Solution:

# Check disk usage
docker system df

# Remove unused volumes
docker volume prune

# List all volumes
docker volume ls

# Remove specific volume (use with caution!)
docker volume rm volume_name

# Clean everything (development only)
docker compose down -v
docker system prune -a --volumes

⚑ Build Docker Compose Files Visually

No more manual YAML editing! Use our free Docker Compose Generator to create production-ready configurations with drag-and-drop simplicity.

Try the Generator β†’

Frequently Asked Questions

What's the difference between docker-compose and Docker Compose v2? +

docker-compose (v1): Standalone Python tool, requires separate installation. Slower startup.

Docker Compose (v2): Written in Go, built into Docker, faster startup, uses docker compose instead of docker-compose. Recommended for all new projects.

Usage: docker compose (v2) vs docker-compose (v1)

How do I restart just one service without affecting others? +

Use the service-specific restart command:

docker compose restart postgres

Other services remain unaffected. You can also use stop and start separately:

docker compose stop postgres
docker compose start postgres
Can I use Docker Compose for production deployments? +

Yes, but with caveats. Docker Compose is suitable for:

  • Small production deployments (single server)
  • Staging environments
  • Development and testing

For large-scale production, consider:

  • Kubernetes: Multi-node orchestration, auto-scaling, advanced networking
  • Docker Swarm: Lighter than Kubernetes, built-in to Docker
How do I access container data from the host system? +

Use volumes to mount directories on the host into containers:

volumes:
  - /host/path:/container/path         # Bind mount
  - named_volume:/container/path        # Named volume
  - ./relative/path:/container/path     # Relative path

Named volumes are managed by Docker and persist data independently. Bind mounts link directly to host directories. For databases, always use named volumes for data persistence.

What happens to data when I run "docker compose down"? +

docker compose down: Stops and removes containers and networks, but PRESERVES named volumes.

docker compose down -v: Also removes named volumes (⚠️ deletes data!).

Best practice: Always use down without -v unless you specifically want to delete data.

Key Takeaways

πŸš€ Next Steps
\xF0\x9F\x92\x99 Tip\xF0\x9F\x93\x9A Get Bundle \x244.99