# compose.override.yaml for Development — Docker Compose

Source: https://www.skillbyai.com/en/docker-compose/e-override

> Loaded automatically.

## Automatic merge

If a `compose.override.yaml` exists next to `compose.yaml`, Compose loads and **merges** it automatically. Use it for development conveniences: published debug ports, bind-mounted source code, verbose logging. Merging rules: single values (like `LOG_LEVEL`) are replaced, lists such as `ports` are combined, and maps are merged key by key. Passing `-f compose.yaml` explicitly skips the automatic override.

## One base, small differences

Override files, multiple -f flags and profiles keep environment differences explicit.

![Three ideas: override files, production files, profiles.](assets/figures/docker-compose/section-7-map.svg) — Figure 7.1 — Overrides, production files and profiles.

## The override file

Development-only additions for the API.

```yaml
services:
  api:
    ports:
      - "3000:3000"
    environment:
      LOG_LEVEL: debug
    volumes:
      - ./api:/app
```

## With and without the override, run

I ran this with Docker Compose v2.38.1 and jq in the demo "shop" project. docker compose config parses, interpolates, merges and validates the files without starting containers; the Docker daemon was not running, so nothing was started. By default the API gets LOG_LEVEL debug, port 3000 and a bind mount from the override; loading compose.yaml alone gives LOG_LEVEL info, no published ports and no mounts.

```bash
echo "compose.yaml + compose.override.yaml (default):"
docker compose config --format json | jq -c ".services.api | {LOG_LEVEL: .environment.LOG_LEVEL, ports: [.ports[]?.published], volumes: [.volumes[]?.type]}"
echo "compose.yaml only:"
docker compose -f compose.yaml config --format json | jq -c ".services.api | {LOG_LEVEL: .environment.LOG_LEVEL, ports: [.ports[]?.published], volumes: [.volumes[]?.type]}"
```

Output:

```
compose.yaml + compose.override.yaml (default):
{"LOG_LEVEL":"debug","ports":["3000"],"volumes":["bind"]}
compose.yaml only:
{"LOG_LEVEL":"info","ports":[],"volumes":[]}
```

**Quiz:** When is compose.override.yaml loaded?

- [ ] Only in production
- [x] Automatically, unless you pass -f files explicitly
- [ ] Never; it must be named in every command
- [ ] Only with --profile override

*Answer:* Automatically, unless you pass -f files explicitly. It exists for local development tweaks.
