SyntaxStudy
Sign Up
Docker Docker Compose for Development Workflows
Docker Beginner 1 min read

Docker Compose for Development Workflows

Docker Compose excels in development by providing every developer with an identical, isolated stack that starts with a single command. Source code is mounted as a bind mount so changes appear instantly. A nodemon or equivalent file watcher inside the container restarts the process on code changes, providing a hot-reload developer experience entirely inside Docker. Compose override files (docker-compose.override.yml or compose.override.yaml) are automatically merged with the base compose.yaml. This pattern is used to keep the base file production-oriented and the override file development-specific: mounting source code, exposing debugger ports, enabling verbose logging, and adding development tools like Mailhog. Environment variable substitution in Compose reads from a .env file in the same directory. Variables in the .env file are substituted into the compose.yaml using ${VARIABLE} syntax. This enables a single compose.yaml to work across development, staging, and CI by changing only the .env file, which is never committed to version control.
Example
# compose.override.yaml  (dev additions, never deployed to prod)
services:
  api:
    build:
      target: dev
    command: ["node", "--watch", "src/server.js"]
    volumes:
      - ./src:/app/src
      - ./config:/app/config
    ports:
      - "9229:9229"
    environment:
      NODE_ENV: development
      LOG_LEVEL: debug

  mailhog:
    image: mailhog/mailhog
    ports:
      - "8025:8025"
      - "1025:1025"

# .env (never committed)
# POSTGRES_PASSWORD=devpassword
# JWT_SECRET=devsecret

# compose.yaml references env vars:
# environment:
#   POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

# Dev workflow
# docker compose up --build
# docker compose exec api sh
# docker compose restart api
# docker compose run --rm api npm test