Docker Compose gives you three ways to split and reuse configurations. They look similar but work at different levels and serve different purposes.

Override files: project-level merge

Override files are merged with your main compose.yml at the project level. compose.override.yml is loaded automatically; additional files require the -f flag:

# compose.override.yml is loaded automatically
docker compose up

# Explicit merge
docker compose -f compose.yml -f compose.prod.yml up

Mappings are merged (override wins), arrays are concatenated:

# compose.yml
services:
  app:
    image: myapp
    environment:
      LOG_LEVEL: debug
    ports:
      - "3000:3000"

# compose.override.yml
services:
  app:
    environment:
      LOG_LEVEL: info   # Overrides debug
    ports:
      - "9229:9229"     # Appended, not replaced

Result: app gets LOG_LEVEL=info and both ports exposed.

extends: service-level inheritance

extends lets a service inherit configuration from another service definition, in the same file or another file:

# base.yml
services:
  base:
    image: myapp
    environment:
      LOG_FORMAT: json
      METRICS_ENABLED: "true"
    labels:
      com.company.team: platform

# compose.yml
services:
  api:
    extends:
      file: base.yml
      service: base
    environment:
      PORT: "8080"    # Added on top of inherited env vars

  worker:
    extends:
      file: base.yml
      service: base
    environment:
      PORT: "8081"

api and worker both get the base environment and labels, each adding their own PORT.

Note: extends does not inherit depends_on, links, or volumes_from — you need to redeclare those in each service.

include: isolated sub-projects

include pulls in another Compose file as a self-contained unit. Unlike override files, the included file is parsed in isolation with its own working directory and its own .env file:

# compose.yml
include:
  - path: ./monitoring/compose.yml
  - path: ./database/compose.yml

services:
  app:
    image: myapp
    depends_on:
      - postgres   # Service defined in database/compose.yml

The included file’s services are merged into the project, but the included file cannot see or override services in the parent. It’s a one-way import.

Key differences at a glance

MechanismScopeContext
Override filesProject (all services)Shared
extendsSingle serviceShared
includeFull sub-projectIsolated

Further reading