Module P-4·7 min read

Compose v2 workflows, profiles, overrides, and managing boot order with depends_on and health checks.

Written by Jatin Jain Saraf · Architect of SupraScan

Docker Compose for Local Dev

Introduction

Running docker run manually with ten different flags (-p, -v, -e, --network) works for a single container. But a real application rarely consists of a single container.

A modern SaaS application might require:

  1. A Next.js frontend
  2. A Node.js API
  3. A PostgreSQL database
  4. A Redis cache

Typing out four complex docker run commands in the exact right order every time you want to develop locally is unsustainable.

Docker Compose is an orchestration tool that allows you to define your entire multi-container environment in a single declarative YAML file. In this module, we will explore Compose v2, managing boot order, and utilizing overrides for different environments.


The Reality of Compose V2

If you learned Docker years ago, you probably used docker-compose (with a hyphen). This was Compose V1, written in Python.

Docker has since completely rewritten Compose in Go and integrated it directly into the Docker CLI as a plugin.

  • Old Way: docker-compose up
  • New Way: docker compose up

Similarly, the configuration file is now officially named compose.yaml (though docker-compose.yml is still supported for backwards compatibility). Always prefer Compose V2 and compose.yaml for new projects.


Anatomy of a compose.yaml

A compose.yaml file defines services, networks, and volumes.

Here is a complete local development environment for a full-stack application:

# compose.yaml
name: my-saas-app
 
services:
  # 1. The PostgreSQL Database
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secretpassword
      POSTGRES_DB: saas_db
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U admin -d saas_db"]
      interval: 5s
      timeout: 5s
      retries: 5
 
  # 2. The Redis Cache
  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"
 
  # 3. The Node.js API
  api:
    build:
      context: ./api
      target: dev # Target a specific stage in a multi-stage Dockerfile
    environment:
      DATABASE_URL: postgres://admin:secretpassword@db:5432/saas_db
      REDIS_URL: redis://cache:6379
    ports:
      - "8080:8080"
    volumes:
      - ./api:/app          # Bind mount for hot-reloading
      - /app/node_modules   # Anonymous volume to protect container's node_modules
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
 
volumes:
  pgdata: # Declare the named volume used by the db service

What Compose does for you:

When you run docker compose up, Compose automatically:

  1. Creates a custom bridge network named my-saas-app_default.
  2. Creates the pgdata volume if it doesn't exist.
  3. Builds the api image from the ./api directory.
  4. Starts all containers and attaches them to the custom network, enabling internal DNS (the api can connect to db:5432).
  5. Streams the interleaved logs from all three containers to your terminal.

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...