Docker Compose Profiles for Managing Multiple Environments
Quick answer
Docker Compose profiles let you tag services so they start only when you activate a matching profile. This keeps one Compose file usable for development,...
Docker Compose profiles let you tag services so they start only when you activate a matching profile. This keeps one Compose file usable for development, testing, and debugging without starting everything every time. Profiles work best for optional services such as debug tools and test dependencies, while override files remain better for changing settings between environments.
How Do Compose Profiles Work?
Each service can declare one or more profiles. A service with no profile always starts. A service with profiles starts only when at least one of its profiles is enabled, either through the command line or an environment variable.
services:
api:
build: .
ports: ["8080:8080"]
db:
image: postgres:16
adminer:
image: adminer
profiles: ["debug"]
mailhog:
image: mailhog/mailhog
profiles: ["dev", "debug"]
Running docker compose up starts only api and db. Running docker compose --profile debug up also starts adminer and mailhog. You can enable several profiles together, or set the COMPOSE_PROFILES variable to make the choice persistent in a shell or an environment file.
Profiles are supported in current Compose versions, but behavior around dependencies has changed over time. Check the documentation for your Compose version when a profiled service is referenced by another one.
What Are Good Use Cases for Profiles?
Profiles shine when a project has services that only some people or workflows need. Keeping them in the same file avoids duplicated definitions and makes the full topology visible in one place.
- Debug tools: database admin interfaces, mail catchers, and tracing viewers that you rarely need.
- Test dependencies: extra databases, mock servers, or message brokers used only by integration tests.
- One-off jobs: migration or seed containers you run on demand with docker compose run.
- Heavy components: search clusters or monitoring stacks that slow down laptops, so developers opt in.
The benefit is mostly ergonomic. New team members run a single command and get a minimal working stack, while specialized tools stay one flag away.
When Are Override Files a Better Fit?
Profiles decide which services run. They do not change how a service is configured. If development needs a bind mount, a debug port, or different environment variables, while production needs none of those, override files are the right tool.
Compose automatically merges docker-compose.yml with docker-compose.override.yml, and you can pass additional files with the -f option. The later files override or extend the earlier ones, which lets you keep a stable base and layer environment-specific changes on top.
docker compose -f compose.yml -f compose.prod.yml up -d
A practical combination is common: a base file with profiles for optional services, plus override files for settings that differ between environments. Keep each mechanism focused on one job so the setup stays understandable.
What Pitfalls Should You Avoid?
The most frequent confusion comes from dependencies. If a service without a profile depends on a profiled service, Compose may refuse to start or you may need to enable the profile explicitly. Design dependencies so that core services never rely on optional ones.
- Do not hide required services behind profiles, or new developers will see a broken stack.
- Document the available profiles in the README, with the command to start each combination.
- Avoid using profiles as a substitute for separate production configuration, since mixing both in one file invites accidents.
- Keep secrets out of the Compose file and load them through environment files or a secret mechanism.
Also remember that stopping the stack requires the same profile flags, otherwise profiled containers can remain running. Using the same environment variable for up and down avoids that mistake.
Frequently Asked Questions
Does a service without profiles always start?
Yes. Services without a profile are part of the default set and start with every docker compose up.
Can a service belong to several profiles?
Yes. List multiple profiles, and the service starts when any one of them is active.
Can I use profiles instead of separate files for production?
It is possible but usually unwise. Separate override files make production differences explicit and reduce accidental exposure of debug services.
How do I run a profiled one-off service?
Use docker compose run with the service name. Explicitly targeted services start even when their profile is not enabled, but confirm this in the documentation for your version.
Summary
Use profiles to switch optional services on and off, and use override files to change configuration between environments. Keep core services profile-free, document your profiles, and check the Compose documentation for version-specific behavior.