Resourcesโ€บDevOps Hacksโ€บDocker Compose Hacks for Local Development
๐ŸšขDevOps Hacksโ€” Docker Compose Hacks for Local Developmentโฑ 6 min

Docker Compose Hacks for Local Development

Docker Compose patterns that make local development faster, more consistent, and closer to production.

๐Ÿ“…February 9, 2026โœTechTwitter.iodocker-composedevopslocal-devdocker

Docker Compose Is Underrated

Most developers use Docker Compose for the basics: spin up a database and cache alongside their app. But Compose has features that can make your local dev environment much more powerful.


1. Health Checks + depends_on Conditions

The classic problem: your app starts before the database is ready and crashes.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 5s
      timeout: 3s
      retries: 5

  app:
    build: .
    depends_on:
      db:
        condition: service_healthy  # Wait for healthy, not just started
    environment:
      DATABASE_URL: postgres://user:password@db:5432/myapp

service_healthy waits for the health check to pass, not just for the container to start.


2. Override Files for Environment Differences

Use multiple Compose files for different environments:

# docker-compose.yml โ€” base config shared everywhere
services:
  app:
    build: .
    environment:
      NODE_ENV: development

  db:
    image: postgres:16
# docker-compose.override.yml โ€” auto-loaded in development
services:
  app:
    volumes:
      - .:/app  # Mount source for hot reload
      - /app/node_modules  # Preserve container's node_modules
    ports:
      - "3000:3000"
    environment:
      DEBUG: "true"
# docker-compose.prod.yml โ€” used explicitly in CI/staging
services:
  app:
    image: myapp:${VERSION}  # Use pre-built image, not build
    restart: always
# Development (uses base + override automatically):
docker compose up

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

3. Profiles for Optional Services

Not everyone needs every service. Use profiles:

services:
  app:
    build: .
    # No profile = always starts

  db:
    image: postgres:16
    # No profile = always starts

  redis:
    image: redis:7
    profiles: ["cache"]  # Only starts with --profile cache

  mailhog:
    image: mailhog/mailhog
    profiles: ["email"]  # Only starts with --profile email

  prometheus:
    image: prom/prometheus
    profiles: ["monitoring"]
# Default: just app and db
docker compose up

# With email testing
docker compose --profile email up

# With everything
docker compose --profile cache --profile email --profile monitoring up

4. Volume for Faster Node Modules

Mounting your source code for hot reload but keeping node_modules in the container:

services:
  app:
    build: .
    volumes:
      - .:/app                    # Mount source code
      - node_modules:/app/node_modules  # Named volume for deps
volumes:
  node_modules:  # Declare the named volume

The named volume is managed by Docker, persists between restarts, and isn't overwritten by the source mount.


5. Watch Mode (Compose Watch)

Docker Compose Watch (introduced in Compose 2.22) syncs file changes without volume mounts โ€” faster and more selective:

services:
  app:
    build: .
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
          ignore:
            - node_modules
        - action: rebuild
          path: package.json  # Rebuild when deps change
docker compose watch

Changes to src/ are synced instantly. Changes to package.json trigger a rebuild. No volume mount overhead.


6. Use .env Files Properly

# .env (default, loaded automatically)
DATABASE_URL=postgres://user:pass@db:5432/myapp
REDIS_URL=redis://redis:6379

# .env.local (overrides for your machine, gitignored)
API_KEY=dev-key-abc123
# docker-compose.yml
services:
  app:
    env_file:
      - .env
      - .env.local  # Overrides .env values

Add .env.local to .gitignore. Commit .env with safe defaults for local development only.


7. Useful Aliases

Add to your ~/.bashrc or ~/.zshrc:

alias dc='docker compose'
alias dcu='docker compose up -d'
alias dcd='docker compose down'
alias dcl='docker compose logs -f'
alias dcps='docker compose ps'
alias dcr='docker compose restart'

# Shortcut: nuke and restart fresh
alias dcfresh='docker compose down -v && docker compose up -d'

Key Takeaways

  • Use depends_on: condition: service_healthy โ€” wait for databases to be ready
  • Override files (docker-compose.override.yml) โ€” different config per environment, no duplication
  • Profiles โ€” optional services that don't clutter default up
  • Named volume for node_modules โ€” avoid the source mount overwriting container deps
  • Compose Watch โ€” file sync without volume mount performance overhead
  • .env + .env.local โ€” shared defaults with per-machine overrides