In this article
Docker Compose profiles control which services are included for a particular use case. They are useful when one Compose file contains optional debugging tools, migration jobs, or development services.
To predict the result of a Compose command, separate two questions:
- Which services enter the application model?
- Which services does the command actually start?
That distinction becomes important when you directly target a profiled service. Compose can activate the target’s profile without starting every other service assigned to that profile. Dependencies introduce another constraint: a reference to an excluded service does not always activate it.
Profiles apply to services
The profiles attribute belongs to a service definition. Services without it are always enabled. A profiled service is ignored when none of its profiles are active, unless a command explicitly targets that service. Other top-level elements are not affected by profiles and remain active in the model (Docker profiles reference).
In other words, profiles select services. They do not conditionally remove top-level networks, volumes, configs, or other non-service elements.
A service can be assigned to one or more profiles:
services:
backend:
image: backend
debugger:
image: debugger
profiles:
- debug
Here, backend is always enabled because it has no profiles attribute. debugger is enabled when debug is active or when a command directly targets debugger.
Enabling profiles explicitly
You can enable a profile with --profile:
docker compose --profile debug up
Alternatively, use the COMPOSE_PROFILES environment variable:
COMPOSE_PROFILES=debug docker compose up
Multiple profiles can be enabled with repeated flags or a comma-separated environment variable:
docker compose --profile frontend --profile debug up
COMPOSE_PROFILES=frontend,debug docker compose up
Docker also documents --profile "*" for enabling all profiles (Using profiles with Compose).
Explicitly enabling a profile makes its assigned services eligible under the application model. Direct service targeting has a narrower command-level effect: it starts the target and its applicable depends_on dependencies, but not unrelated services merely because they share the target’s automatically activated profile (Using profiles with Compose).
Docker’s four-service example
The profiles reference illustrates these rules with four services:
services:
web:
image: web_image
test_lib:
image: test_lib_image
profiles:
- test
coverage_lib:
image: coverage_lib_image
depends_on:
- test_lib
profiles:
- test
debug_lib:
image: debug_lib_image
depends_on:
- test_lib
profiles:
- debug
The relationships are straightforward but produce different outcomes:
webhas no profile, so it is always enabled.test_libbelongs totest.coverage_libbelongs totestand depends ontest_lib.debug_libbelongs todebugbut depends ontest_lib, which belongs totest.
That last dependency demonstrates why depends_on does not universally bring a profile-excluded service into the model.
Documented outcomes
The following results are limited to Docker’s official example (Docker profiles reference).
| Profiles or explicit target | Documented outcome |
|---|---|
| No profile enabled | The application model contains only web. |
test enabled |
The model contains web, test_lib, and coverage_lib. |
debug enabled |
The model contains web and debug_lib, but is invalid because debug_lib depends on the excluded test_lib. |
test and debug enabled |
The model contains all four services. |
Target test_lib |
test_lib and the test profile become active. |
Target coverage_lib |
coverage_lib and the test profile become active; test_lib is pulled in through depends_on. |
Target debug_lib |
The model is invalid because debug_lib and its test_lib dependency have no common profile. |
Enable test and target debug_lib |
Targeting activates debug; test_lib is pulled in, and both debug_lib and test_lib start. |
The important contrast is between coverage_lib and debug_lib.
Both coverage_lib and its dependency test_lib belong to test. When coverage_lib is targeted, its profile becomes active and Docker’s example says that test_lib is pulled in through depends_on.
By comparison, debug_lib belongs to debug, while test_lib belongs to test. Enabling only debug, or targeting only debug_lib, does not activate test. The documented result is an invalid model rather than automatic expansion into the dependency’s profile.
If test is explicitly enabled while debug_lib is targeted, both sides of the relationship are available. Targeting activates debug, while the explicitly enabled test profile makes test_lib available as a dependency.
Targeting a service is not the same as enabling its profile
When you explicitly target a profiled service, Compose adds that service’s profile to the active-profile set. However, the corresponding command starts only the target and its declared depends_on dependencies. Other services sharing the profile are not started unless they are also targeted or the profile is explicitly enabled with --profile or COMPOSE_PROFILES (Using profiles with Compose).
These statements can therefore both be true:
- The targeted service’s profile becomes active.
- Unrelated services assigned to that profile do not start.
Application-model activation and a command’s start set should not be treated as interchangeable.
References other than depends_on also have explicit limits. References through links, extends, or shared-resource syntax such as service:xxx do not automatically activate a service excluded by profiles. Compose returns an error instead (Docker profiles reference).
depends_on does not guarantee readiness
Profile selection determines whether a dependency can participate in the model. It does not show that the dependency is healthy or ready to serve requests.
With short-form depends_on, Compose starts dependency services before the dependent service, but does not wait for those dependencies to become healthy (Compose services reference):
depends_on:
- db
Long-form depends_on can specify a condition such as service_healthy, but that condition is separate from profile activation.
When evaluating a Compose command, ask:
- Which services have no profile?
- Which profiles were explicitly enabled?
- Was a profiled service targeted directly?
- Are its required dependencies available under that profile arrangement?
- Are you asking about model membership or the command’s start set?
- Does the dependency require a separate health condition?
Following those questions keeps profile activation, dependency validity, and service startup from being conflated.
No comments yet