iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Profiles & Overrides

Compose profiles let you conditionally start a subset of services. Each service can declare one or more profiles; services without a profile always run. Use it for optional workers, dev-only tools, demo seeds, or staging-only sidecars — the same compose.yaml ships everywhere, but you start only what the environment needs.

profiles for workers, dev tooling, and demo seeding

EXAMPLE
# compose.yaml
name: shop

services:
  # ALWAYS runs — no profile attached
  api:
    image: shop/api:dev
    ports: ['3000:3000']
    depends_on: [db, redis]
    environment:
      DATABASE_URL: postgres://shop:dev@db:5432/shop

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: shop
      POSTGRES_USER: shop
      POSTGRES_PASSWORD: dev
    volumes: [pgdata:/var/lib/postgresql/data]

  redis:
    image: redis:7-alpine

  # WORKERS — only with --profile workers
  worker:
    image: shop/api:dev
    command: ['node', 'dist/worker.js']
    depends_on: [db, redis]
    profiles: ['workers']

  scheduler:
    image: shop/api:dev
    command: ['node', 'dist/scheduler.js']
    depends_on: [redis]
    profiles: ['workers']

  # DEV TOOLS — only with --profile devtools
  adminer:
    image: adminer:4
    ports: ['8080:8080']
    depends_on: [db]
    profiles: ['devtools']

  redisinsight:
    image: redislabs/redisinsight:latest
    ports: ['8001:8001']
    depends_on: [redis]
    profiles: ['devtools']

  mailhog:
    image: mailhog/mailhog:latest
    ports: ['8025:8025', '1025:1025']
    profiles: ['devtools']

  # DEMO SEED — only with --profile demo
  seed:
    image: shop/api:dev
    command: ['node', 'dist/scripts/seed.js']
    depends_on: [db]
    profiles: ['demo']
    restart: 'no'

  # STAGING ONLY — exposes metrics for the cluster
  metrics-exporter:
    image: shop/metrics-exporter:latest
    ports: ['9091:9091']
    profiles: ['staging']

volumes:
  pgdata: {}

# ===== Usage =====

# Default: api + db + redis only (no workers, no tools)
docker compose up -d

# Add workers
docker compose --profile workers up -d
# Stops api+db+redis already running and adds worker+scheduler.
# Existing containers stay; new ones are created.

# Dev session: workers + tools + the seed
docker compose --profile workers --profile devtools --profile demo up -d

# Tear down a single profile (and keep the rest)
docker compose --profile devtools down

# Resolve the merged compose, confirm which services are selected
docker compose --profile workers config --services

# ===== Patterns to internalise =====

# 1) Default profile = production minimum
# Services without any profile run on every compose up. Keep this list to the
# services your app truly needs to function in production.

# 2) Profile per ROLE, not per environment
# Good:  'workers', 'devtools', 'demo', 'staging-only', 'metrics'
# Bad:   'production' (too broad), 'developer' (too vague)
# A service can be in multiple profiles ('workers', 'staging').

# 3) Multiple profiles compose ADDITIVELY
# --profile workers --profile devtools starts BOTH sets, plus the no-profile set.

# 4) Override files still work
# Combine with -f compose.dev.yaml for cross-cutting tweaks per environment.

# ===== Common usages =====

# Local dev with everything:
# docker compose --profile workers --profile devtools up -d

# CI smoke test (no workers, no dev tools):
# docker compose up -d --wait

# One-shot seed:
# docker compose --profile demo run --rm seed

# Staging with metrics:
# docker compose --profile workers --profile staging up -d

# ===== Pitfalls =====
# - Putting 'db' or 'redis' in a profile -> nothing starts; api fails
#   (always keep core infra services profile-less)
# - Forgetting profiles flag in CI -> the worker never runs, jobs back up
# - Profile names that match service names -> confusion in logs
# - Using profiles to gate SECRETS instead of env files -> secrets still in
#   compose.yaml; use env_file + .env per environment instead

# ===== Decision tree =====
# Always needed?           no profile
# Optional dev tooling?     'devtools'
# Optional background job?  'workers'
# One-shot scripts?         own profile + 'docker compose run --rm'
# Environment-specific?     environment profile + override file

Why it matters

Profile the optional bits, keep the core infra profile-less. The same compose.yaml then ships to laptops (with dev tools + workers + demo data) and to a tiny staging VM (just api + db + redis) — and the difference is one command line flag, not a separate file per environment.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# Compose profiles allow optional services
services:
    metrics:
        image: grafana/grafana
        profiles: [observability]
# Run with: docker compose --profile observability up
Try it Yourself »

Discussion

Loading…