docker.recipes
Fundamentals6 min read

Docker Compose Profiles: Running Service Subsets

Use profiles to selectively start services for development, testing, debugging, or production scenarios.

01What Profiles Solve

Not every service needs to run in every environment. You might want debugging tools in development but not production, or optional monitoring that's off by default. Profiles let you define service groups that only start when explicitly requested.

02Defining Profiles

Add a profiles key to any service. Services with profiles won't start by default—you must explicitly enable their profile. Services without profiles always start.
1services:
2 # Always starts (no profile)
3 app:
4 image: myapp:latest
5 ports:
6 - "8080:8080"
7
8 # Always starts (no profile)
9 db:
10 image: postgres:16-alpine
11 volumes:
12 - db_data:/var/lib/postgresql/data
13
14 # Only starts with --profile debug
15 debugger:
16 image: busybox
17 profiles: ["debug"]
18 command: sleep infinity
19
20 # Only starts with --profile monitoring
21 prometheus:
22 image: prom/prometheus:latest
23 profiles: ["monitoring"]
24 ports:
25 - "9090:9090"
26
27 # Starts with EITHER debug OR monitoring profile
28 grafana:
29 image: grafana/grafana:latest
30 profiles: ["debug", "monitoring"]
31 ports:
32 - "3000:3000"
33
34volumes:
35 db_data:

A service can belong to multiple profiles. It starts if ANY of its profiles are activated.

03Running with Profiles

Use the --profile flag (repeatable) or COMPOSE_PROFILES environment variable to activate profiles.
1# Start only default services (app, db)
2docker compose up -d
3
4# Start default + debug services
5docker compose --profile debug up -d
6
7# Start default + monitoring services
8docker compose --profile monitoring up -d
9
10# Start multiple profiles
11docker compose --profile debug --profile monitoring up -d
12
13# Using environment variable
14export COMPOSE_PROFILES=debug,monitoring
15docker compose up -d
16
17# In .env file
18COMPOSE_PROFILES=monitoring

04Development vs Production Profiles

A common pattern: development tools in dev profile, production optimizations in prod profile.
1services:
2 app:
3 image: myapp:latest
4 ports:
5 - "8080:8080"
6 environment:
7 - DEBUG=${DEBUG:-false}
8
9 db:
10 image: postgres:16-alpine
11
12 # Development tools
13 mailhog:
14 image: mailhog/mailhog
15 profiles: ["dev"]
16 ports:
17 - "1025:1025" # SMTP
18 - "8025:8025" # Web UI
19
20 adminer:
21 image: adminer
22 profiles: ["dev"]
23 ports:
24 - "8081:8080"
25
26 # Production services
27 redis:
28 image: redis:alpine
29 profiles: ["prod"]
30
31 nginx:
32 image: nginx:alpine
33 profiles: ["prod"]
34 ports:
35 - "80:80"
36 - "443:443"
37 volumes:
38 - ./nginx.conf:/etc/nginx/nginx.conf:ro

Run with profile: docker compose --profile dev up -d (development) or docker compose --profile prod up -d (production)

05Profiles and Dependencies

When a profiled service depends on another profiled service, both profiles must be active. Be careful with cross-profile dependencies.
1services:
2 app:
3 image: myapp:latest
4 depends_on:
5 - db
6
7 db:
8 image: postgres:16-alpine
9
10 # This won't work without the monitoring profile active
11 grafana:
12 image: grafana/grafana
13 profiles: ["monitoring"]
14 depends_on:
15 - prometheus
16
17 prometheus:
18 image: prom/prometheus
19 profiles: ["monitoring"]
20
21 # Better: depend on non-profiled services when possible
22 metrics-exporter:
23 image: prom/node-exporter
24 profiles: ["monitoring"]
25 # No dependency on prometheus - works independently

If service A (profile: debug) depends on service B (profile: monitoring), you must enable BOTH profiles or A won't start.

06Practical Profile Patterns

Real-world profile configurations for common scenarios.
1services:
2 app:
3 image: myapp:latest
4
5 db:
6 image: postgres:16-alpine
7
8 # Testing: Run integration tests
9 test-runner:
10 image: myapp:latest
11 profiles: ["test"]
12 command: pytest
13 depends_on:
14 - db
15
16 # Seeding: Load sample data
17 seeder:
18 image: myapp:latest
19 profiles: ["seed"]
20 command: python seed_data.py
21 depends_on:
22 - db
23
24 # Backup: On-demand database backup
25 backup:
26 image: postgres:16-alpine
27 profiles: ["backup"]
28 volumes:
29 - ./backups:/backups
30 command: pg_dump -h db -U postgres mydb > /backups/backup.sql
31 depends_on:
32 - db
33
34 # Debugging: Interactive shell
35 shell:
36 image: myapp:latest
37 profiles: ["shell"]
38 stdin_open: true
39 tty: true
40 command: /bin/bash
41 depends_on:
42 - db

Run these profiles on-demand: --profile test for tests, --profile seed for seeding, --profile backup for backups, --profile shell for interactive access.