Skip to main content

Compose Profiles

A Docker Compose feature that tags services with profile names, allowing them to be selectively started. Services without a profile always start — services with a profile only start when that profile is explicitly activated with --profile.

Compose Profiles — Selectively Starting Services

What Is a Compose Profile in Simple Terms?

Not every developer needs every service running every time. A frontend developer working on the UI does not need the data analytics pipeline running. A backend developer does not always need the email service running. Compose profiles let you mark optional services with a label, and they only start when you explicitly request that profile.

YAML
version: "3.8"
services:
api:
image: payment-api:latest # no profile = ALWAYS starts
postgres:
image: postgres:15 # no profile = ALWAYS starts
analytics:
image: analytics-service:latest
profiles:
- analytics # only starts with --profile analytics
mailhog:
image: mailhog/mailhog
profiles:
- email # only starts with --profile email
debug-ui:
image: adminer
profiles:
- debug # only starts with --profile debug
- tools # also starts with --profile tools

Using Profiles

Bash
# Start only base services (api + postgres)
docker compose up -d
# analytics, mailhog, debug-ui do NOT start
# Start with analytics pipeline
docker compose --profile analytics up -d
# api, postgres, analytics all start
# mailhog, debug-ui do NOT start
# Start with multiple profiles
docker compose --profile analytics --profile email up -d
# api, postgres, analytics, mailhog all start
# Start everything
docker compose --profile "*" up -d
# List services that would start for a profile
docker compose --profile analytics config --services

Practical Profile Patterns

YAML
services:
api: # always on
postgres: # always on
redis: # always on
# Only for developers who need to receive emails locally
mailhog:
profiles: [email]
# Only for debugging database queries
adminer:
profiles: [debug]
# Only in CI for integration tests
test-runner:
profiles: [ci]
command: ["npm", "run", "test:integration"]
# Only for load testing
k6:
image: grafana/k6
profiles: [loadtest]
volumes:
- ./k6:/scripts
command: ["run", "/scripts/payment-load-test.js"]
Tip

Use profiles for any service that is not always needed in development — database admin UIs, email catchers, monitoring tools, test runners, load testing tools. This keeps docker compose up fast for daily development while making all optional tools available when needed.

Frequently Asked Questions

What problem do Compose profiles solve that separate compose files don't?

Before profiles, teams either ran every service in a compose file regardless of need (wasting resources on tools like a debug UI or seed-data job that aren't needed every time) or maintained parallel compose files to exclude them. Profiles let one file describe everything, with optional services tagged by profile name and only started when that profile is explicitly activated — so a single `docker compose up` stays lean by default while `--profile debug` pulls in the extras on demand.

What's a common mistake when using Compose profiles?

Forgetting that a profiled service is also skipped by `docker compose up <service-name>` unless its profile is active — engineers sometimes assume naming a service directly bypasses the profile gate, and get confused when it doesn't start. Also, a service with no profile listed always runs, so retrofitting profiles onto an existing file requires auditing every service, not just the ones you intend to make optional.