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…