## Intro

Docker Compose profiles let teams define optional services in one compose file and activate them only when needed. A profile is a label attached to a service, and you enable that label with the `--profile` flag or the `COMPOSE_PROFILES` environment variable. This is useful for running a full development stack with debugging tools, or for splitting production services from maintenance jobs.

However, profiles introduce a class of configuration mistakes that are easy to make and sometimes hard to notice. A service silently not starting because its profile was not activated is a common cause of confusing outages. Misplaced profile definitions, typos in profile names, or forgotten profile flags in CI pipelines can lead to missing databases, absent background workers, or broken one-off tasks.

This guide covers the most frequent Docker Compose profile configuration mistakes, how to detect them, how to recover, and how to prevent them from happening again. Every section includes a concrete command and the expected output, so you can verify your environment immediately.

## How Docker Compose Profiles Work

Before looking at mistakes, let's clarify the correct syntax. In a compose file, the `profiles` key is placed under a service definition, not at the top level:

```yaml
version: "3.9"
services:
  app:
    image: nginx:1.25
    ports:
      - "8080:80"
  debug-tools:
    image: busybox:1.36
    profiles: ["debug"]
    command: tail -f /dev/null
```

Here `app` has no profiles, so it is always started. The `debug-tools` service belongs to the `debug` profile. To start it, you must explicitly enable the profile:

```bash
docker compose --profile debug up -d
```

Or set the environment variable:

```bash
export COMPOSE_PROFILES=debug
docker compose up -d
```

To check which services are enabled for a given profile without starting anything, use:

```bash
docker compose --profile debug config --services
```

Expected output:

```
app
debug-tools
```

If you run `docker compose config --services` without any profile, only `app` appears. This is the first place mistakes hide: the file is valid, but the active set of services is smaller than expected.

## Common Profile Configuration Mistakes

### 1. Forgetting to Activate a Required Profile

A developer defines a `db` profile for the database service and expects it to be running after `docker compose up -d`. But without `--profile db`, the database container never starts. The application then fails to connect.

**Why it happens:** The compose file looks correct, and the developer may not realize that profiles are opt-in. The service is omitted silently.

**How to detect:** List the services that would be started:

```bash
docker compose config --services
```

If the database is missing, compare with the full service list:

```bash
docker compose config --profiles
```

This shows all profiles defined. Expected output for a file with `db` and `debug` profiles:

```
db
debug
```

**How to recover:** Activate the missing profile and start again:

```bash
docker compose --profile db up -d
```

**How to prevent:** Define a default profile in the compose file using the `COMPOSE_PROFILES` environment variable in a `.env` file, or document the required profile in the project README. For automated environments, set the profile in the CI pipeline or in a wrapper script.

### 2. Putting profiles at the Wrong Level

A common syntax mistake is placing `profiles` under the top-level `services` key or at the root of the file:

```yaml
services:
  profiles: ["debug"]   # wrong
  app:
    image: nginx
```

When you run `docker compose config`, you may see an error like:

```
services.profiles must be a mapping
```

Or the file may be accepted but the profile is ignored, leading to the service always starting.

**Why it happens:** Misunderstanding the YAML structure or copy-pasting from an incorrect example.

**How to detect:** Validate the compose file:

```bash
docker compose config
```

Look for warnings or unexpected service definitions. Also check with `docker compose config --profiles` to see if the profile is recognized.

**How to recover:** Move the `profiles` key inside the intended service definition:

```yaml
services:
  app:
    image: nginx
    profiles: ["debug"]
```

**How to prevent:** Use a linter or a YAML schema validation in your editor. Many editors highlight structural errors in compose files.

### 3. Typos in Profile Names

A service is assigned to profile `debug`, but you activate `--profile dbug`. The service does not start, and the mistake is not obvious because the command succeeds without error.

**Why it happens:** Manual typing or inconsistent naming across scripts.

**How to detect:** Compare the active profile with the profiles defined in the file:

```bash
docker compose config --profiles
# shows available profiles
docker compose config --services --profile dbug
# shows only services in dbug, if any
```

**How to recover:** Activate the correct profile name:

```bash
docker compose --profile debug up -d
```

**How to prevent:** Use a single source of truth for profile names, such as a Makefile target or a shell script that contains the profile list, and avoid typing them manually.

### 4. Profiles in Override Files Not Merging as Expected

Compose supports multiple files, like `docker-compose.yml` and `docker-compose.override.yml`. Profiles in an override file can add or remove profiles from the base service. If the override file is not loaded, the profile may be missing.

**Why it happens:** The override file is not present, or the command does not include the `-f` flag to load the correct files.

**How to detect:** Run `docker compose config` and inspect which services have profiles. You can also use `docker compose config --profiles` to list all profiles.

**How to recover:** Ensure the override file is loaded:

```bash
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
```

**How to prevent:** Explicitly list all compose files in your commands, or use a wrapper script. Avoid relying on implicit file discovery when multiple files exist.

### 5. Profile Activation in CI/CD Pipelines

A CI pipeline runs `docker compose up -d` without the required profile, and tests fail because supporting services are missing.

**Why it happens:** The profile flag is not part of the pipeline configuration, or the environment variable is not set in the runner.

**How to detect:** Add a step to the pipeline that prints the active services:

```bash
docker compose config --services
```

**How to recover:** Update the pipeline to set the profile:

```bash
export COMPOSE_PROFILES=test
docker compose up -d
```

**How to prevent:** Store the profile in a `.env` file used by the pipeline, and review the `.env` file as part of code changes.

## Verification and Diagnostics

After any change to profiles, verify the effective configuration and the running containers.

### Effective Configuration

Run `docker compose config` to see the final merged YAML. Check for unexpected profile assignments or missing services. Use `--services` to list the services that would be started with the current profiles.

Example:

```bash
docker compose --profile debug config --services
```

Expected output includes both the always-on service and the debug service:

```
app
debug-tools
```

### Container Status

After starting the stack, confirm that the expected containers are running:

```bash
docker compose ps
```

Look for the desired services and their state. If a service is not running, check its logs:

```bash
docker compose logs <service-name>
```

### Debugging Profile Activation

If you suspect a profile was not activated, use the `--profiles` flag to see all profiles defined in the file:

```bash
docker compose config --profiles
```

Then manually check which services belong to each profile by examining the YAML or using:

```bash
docker compose config | grep -A2 -B2 'profiles:'
```

This shows the context around each `profiles` key.

## Failure Modes and Recovery

Profiles can fail in ways that are not immediately obvious. Here are specific failure modes and how to recover.

### Missing Database Service

Symptom: Application cannot connect to database.

Check:

```bash
docker compose config --services
```

If the database service is absent, activate its profile:

```bash
docker compose --profile db up -d
```

Verify:

```bash
docker compose ps
```

The database container should now be listed and healthy.

### Background Worker Not Processing Jobs

Symptom: Queue grows but no jobs are processed.

Check whether the worker service has a profile and is not started:

```bash
docker compose config --services
```

Start the worker with its profile:

```bash
docker compose --profile worker up -d
```

Check logs to confirm processing:

```bash
docker compose logs -f worker
```

### One-off Maintenance Task Did Not Run

A service intended for a one-off task, like database migration, is defined with a profile but the profile was not activated when running `docker compose run`.

Correct command:

```bash
docker compose --profile migrate run migrate
```

Without the profile, `docker compose run migrate` fails with "no such service: migrate".

### Rolling Back a Profile Change

If a profile change causes problems, revert to the previous compose file. The simplest rollback is to restore the previous version from version control:

```bash
git checkout -- docker-compose.yml
```

Then restart the stack:

```bash
docker compose down
docker compose up -d
```

If you need to temporarily disable a profile without changing the file, you can set `COMPOSE_PROFILES` to an empty string:

```bash
export COMPOSE_PROFILES=
docker compose up -d
```

This starts only the services without profile assignments.

## Operations Checklist for Profile Changes

Use this checklist before and after changing profiles in a compose file.

Before changing:

- [ ] Identify the service(s) affected by the profile change.
- [ ] Note the current active profiles (`COMPOSE_PROFILES` or `--profile` flags in use).
- [ ] Confirm the compose file is valid: `docker compose config`.
- [ ] Record the current running containers: `docker compose ps`.

After changing:

- [ ] Validate the new configuration: `docker compose config --services`.
- [ ] Start the stack with the intended profiles.
- [ ] Check that all expected services are running: `docker compose ps`.
- [ ] Verify application functionality (e.g., database connection, worker processing).
- [ ] Update documentation or scripts that reference profiles.

Owner and review frequency: assign an owner (e.g., DevOps engineer) to approve profile changes in the compose file, and review profile usage monthly or whenever the deployment environment changes.

## Conclusion

Docker Compose profiles are a powerful way to manage optional services, but they must be used carefully. The most common mistakes are forgetting to activate a profile, misplacing the `profiles` key, and using inconsistent profile names. These mistakes lead to services not starting, which can be difficult to diagnose because the compose file itself is valid.

By following the verification steps in this guide, you can quickly identify missing profiles and recover. The key commands to remember are `docker compose config --services` to see what would start, `docker compose config --profiles` to list available profiles, and `docker compose ps` to check actual running containers.

Prevent future mistakes by standardizing profile names, documenting required profiles, and using environment variables in CI/CD. Always validate the effective configuration before deploying, and include profile checks in your operational runbooks.

With these practices, you can use Docker Compose profiles safely and avoid the silent failures that disrupt development and production environments.