Docker Compose for Developers: Run Your Entire Stack Locally With One Command

Docker Compose for Developers: Run Your Entire Stack Locally With One Command

The biggest source of “works on my machine” bugs is environment differences between developers and production. Docker Compose solves this by defining your entire stack — API, database, Redis, message queue — as code. One docker compose up gives every developer and every CI run the same environment.

TL;DR: Define each service, its image, environment variables, ports, and volumes in compose.yml. Use depends_on with health checks to start services in order. Use named volumes for persistent data. Use profiles for optional services. Override with compose.override.yml for local tweaks.

A complete development stack

# compose.yml
services:
  api:
    build: .                          # Build from Dockerfile in current dir
    ports: ['3000:3000']
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/myapp
      REDIS_URL: redis://cache:6379
      NODE_ENV: development
    volumes:
      - .:/app                         # Hot reload: mount source into container
      - /app/node_modules              # Anonymous volume: keep container's node_modules
    depends_on:
      db:
        condition: service_healthy     # Wait for DB health check to pass
      cache:
        condition: service_started
    command: npm run dev

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pg_data:/var/lib/postgresql/data  # Named volume: persists between restarts
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # Auto-run SQL on first start
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U user -d myapp']
      interval: 5s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    ports: ['6379:6379']

  worker:
    build: .
    command: npm run worker
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/myapp
    depends_on: [db, cache]
    profiles: [worker]  # Only starts with: docker compose --profile worker up

volumes:
  pg_data:

Essential compose commands

# Start everything (build if needed)
docker compose up --build

# Start in background
docker compose up -d

# View logs
docker compose logs -f api          # Follow API logs
docker compose logs -f              # All services

# Shell into running container
docker compose exec api sh
docker compose exec db psql -U user myapp

# Run one-off command
docker compose run --rm api npm run migrate

# Stop and remove containers (keeps volumes)
docker compose down

# Stop and remove everything including volumes (DELETES DATA)
docker compose down -v

# Rebuild just one service
docker compose up -d --build api

Override files for local customization

# compose.override.yml (auto-loaded by compose, git-ignored)
# Override production settings for local dev
services:
  api:
    environment:
      DEBUG: 'true'
      LOG_LEVEL: debug
    volumes:
      - .:/app  # Extra volume for hot reload

# Use separate files for different environments:
docker compose -f compose.yml -f compose.prod.yml up
  • ✅ Always add healthcheck to DB and cache services — api starts after they are ready
  • ✅ Named volumes for persistent data, anonymous volumes for node_modules
  • ✅ .env file for secrets: docker compose reads it automatically
  • ✅ Profiles for optional services (worker, monitoring, mail)
  • ✅ compose.override.yml for local dev tweaks — add to .gitignore
  • ❌ Never hardcode secrets in compose.yml — use environment variables or .env
  • ❌ Never use compose for production — use Kubernetes or ECS instead

Docker Compose local stacks use the same images as production — the Docker best practices guide ensures those images are production-ready. External reference: Docker Compose documentation.

Recommended Reading

Designing Data-Intensive Applications — The essential book every senior developer needs.

The Pragmatic Programmer — Timeless engineering wisdom for writing better code.

Affiliate links. We earn a small commission at no extra cost to you.

Free Weekly Newsletter

🚀 Don’t Miss the Next Cheat Code

Join 1,000+ senior developers getting expert JS, Python, AWS and system design secrets weekly.

✓ No spam✓ Unsubscribe anytime

Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply