Skip to content

Fix: docker-compose.override.yml Not Working — Override File Ignored or Not Merged

FixDevs · (Updated: )

Part of:  Docker, DevOps & Infrastructure

Quick Answer

How to fix docker-compose.override.yml not being applied — file naming, merge behavior, explicit file flags, environment-specific configs, and common override pitfalls.

The Problem

A docker-compose.override.yml file exists but its settings aren’t applied:

# docker-compose.override.yml — expected to add volume mount
services:
  app:
    volumes:
      - ./src:/app/src
    environment:
      DEBUG: "true"
docker compose up
# Container starts without the volume mount or DEBUG env var
# Override file is silently ignored

Or an explicit -f flag stops the override from loading:

docker compose -f docker-compose.yml up
# Only docker-compose.yml loaded — override.yml skipped entirely

Or multiple override files conflict:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up
# docker-compose.override.yml NOT loaded — explicit -f disables auto-loading

In a team setting, this manifests as “works on my machine” tickets that consume hours. One developer’s environment uses the override (because they run docker compose up from the right directory) and another’s silently does not, because they aliased the command to always pass -f docker-compose.yml. The dev environment looks identical from the outside but uses the wrong config — and the bug only surfaces when a test fails that relied on a mounted volume or an env var.

Why This Happens

Docker Compose has an auto-merge feature: when you run docker compose up with no -f flags, it automatically merges docker-compose.yml with docker-compose.override.yml if both files exist in the current directory.

This auto-merge only happens under specific conditions:

  • Exact filename required — the file must be named docker-compose.override.yml (not docker-compose.override.yaml, not override.yml). The .yml extension is required, not .yaml, unless your base file uses .yaml.
  • Must be in the same directory — both files must be in the same directory where you run docker compose.
  • -f flag disables auto-loading — as soon as you use -f to specify any file, Docker Compose stops auto-loading and only uses the files you explicitly listed.
  • Docker Compose v1 vs v2docker-compose (v1, Python) vs docker compose (v2, Go plugin) have minor behavioral differences. Some older setups use docker-compose.yml only and don’t support override files in the same way.

The reason this is such a common cause of “dev environment broken silently” tickets is that Docker Compose does not print a banner telling you which files it loaded by default. If you run docker compose up from one directory above your project, Compose searches up the tree, finds the base file, but does not necessarily find the override — and starts containers with the wrong config. There is no error and no warning. The first signal is a missing volume mount or a wrong environment variable, observed by a developer who happens to notice.

A second pitfall: when COMPOSE_FILE is set as an environment variable (often in a developer’s .envrc or .bashrc from a previous project), it takes precedence over file discovery. Compose loads exactly the files listed in COMPOSE_FILE and ignores the override convention entirely. Removing the override is then invisible from the team’s perspective until someone unsets COMPOSE_FILE.

Fix 1: Verify the Filename and Location

The override file must be named exactly docker-compose.override.yml:

# Check what files exist
ls -la docker-compose*.yml docker-compose*.yaml 2>/dev/null

# Correct filename
docker-compose.override.yml
docker-compose.override.yaml (wrong extension if base is .yml)
docker.compose.override.yml (dot instead of hyphen)
override.yml (wrong name)
docker-compose-override.yml (hyphen instead of dot before override)

Verify Compose is actually reading both files:

# Print the merged config — shows what Docker Compose will use
docker compose config

# If override settings appear in the output, the merge is working
# If they don't appear, the override file isn't being loaded

Check the current directory:

pwd
ls docker-compose*.yml

# Must run docker compose from the directory containing both files
# Not from a parent or child directory

Fix 2: Understand Merge Behavior

Docker Compose merges files by overlaying the second file on top of the first. The merge rules differ by field type:

# docker-compose.yml
services:
  app:
    image: myapp:latest
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      API_URL: https://api.example.com
    volumes:
      - data:/app/data

# docker-compose.override.yml
services:
  app:
    ports:
      - "3001:3001"       # ADDS to ports (lists are appended, not replaced)
    environment:
      NODE_ENV: development  # REPLACES this key (mappings are merged by key)
      DEBUG: "true"          # ADDS new key
    volumes:
      - ./src:/app/src       # ADDS to volumes (lists are appended)

Merged result:

services:
  app:
    image: myapp:latest     # from base
    ports:
      - "3000:3000"         # from base
      - "3001:3001"         # from override (appended)
    environment:
      NODE_ENV: development  # override wins
      API_URL: https://api.example.com  # from base
      DEBUG: "true"          # from override
    volumes:
      - data:/app/data       # from base
      - ./src:/app/src       # from override (appended)

Key merge rules:

  • Mappings (objects): Merged by key — override values replace base values for matching keys, new keys are added
  • Sequences (lists): ports, volumes, environment arrays are appended — not replaced
  • Scalar values: Override replaces base

Fix 3: Explicit File Loading with -f

When you need to use -f, include both files explicitly:

# WRONG — only loads base file, override skipped
docker compose -f docker-compose.yml up

# CORRECT — load base + override explicitly
docker compose -f docker-compose.yml -f docker-compose.override.yml up

# Multiple overrides — applied left to right
docker compose \
  -f docker-compose.yml \
  -f docker-compose.override.yml \
  -f docker-compose.local.yml \
  up

Add a Makefile to avoid typing long commands:

# Makefile
dev:
	docker compose up

prod:
	docker compose -f docker-compose.yml -f docker-compose.prod.yml up

ci:
	docker compose -f docker-compose.yml -f docker-compose.ci.yml up --build

Fix 4: Environment-Specific Configuration Pattern

A common pattern uses a base file plus environment-specific overrides:

project/
├── docker-compose.yml           # Base: shared service definitions
├── docker-compose.override.yml  # Dev: auto-loaded, volume mounts, hot reload
├── docker-compose.prod.yml      # Prod: explicit -f required
├── docker-compose.ci.yml        # CI: explicit -f required
└── .env                         # Environment variables for all files
# docker-compose.yml — base (production-ready defaults)
services:
  app:
    image: myapp:${TAG:-latest}
    restart: unless-stopped
    environment:
      NODE_ENV: production
    networks:
      - backend

  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    networks:
      - backend

volumes:
  pgdata:

networks:
  backend:
# docker-compose.override.yml — development (auto-loaded)
services:
  app:
    build:
      context: .
      target: dev          # Use dev stage in multi-stage Dockerfile
    volumes:
      - ./src:/app/src     # Hot reload: mount source code
      - /app/node_modules  # Don't overwrite container's node_modules
    environment:
      NODE_ENV: development
      DEBUG: "app:*"
    ports:
      - "3000:3000"        # Expose port for local access
      - "9229:9229"        # Node.js debugger port

  db:
    ports:
      - "5432:5432"        # Expose DB for local tools (TablePlus, psql)
# docker-compose.prod.yml — production differences
# Usage: docker compose -f docker-compose.yml -f docker-compose.prod.yml up
services:
  app:
    image: registry.example.com/myapp:${TAG}
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 512M

Fix 5: Override Specific Fields

Common patterns for overriding specific service properties:

# Override the build context (useful for CI vs local)
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
      args:
        BUILD_ENV: development

# Override the command (run dev server instead of production server)
services:
  app:
    command: npm run dev
    # Base has: command: node dist/server.js

# Override the entrypoint
services:
  app:
    entrypoint: /bin/sh -c
    command: ["npm run dev"]

# Override health check
services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 3

Remove a value set in the base file — use null to unset:

# docker-compose.yml sets a restart policy
services:
  app:
    restart: unless-stopped

# docker-compose.override.yml removes it for development
services:
  app:
    restart: "no"   # Override to disable restart in dev

Fix 6: Debug Override Merging

When overrides aren’t applying as expected:

# See the fully merged configuration
docker compose config

# See only the config for one service
docker compose config app

# Validate syntax without running
docker compose config --quiet && echo "Config is valid"

# Check which files Docker Compose is reading
docker compose --verbose config 2>&1 | head -20
# Output includes: "Found project name: myproject"
# and lists the config files being merged

# Run with explicit debug output
COMPOSE_FILE=docker-compose.yml:docker-compose.override.yml docker compose config

Check environment variable substitution:

# .env file values are substituted in compose files
# Verify substitution is working:
docker compose config | grep -A5 "environment:"

# If variables show as empty, check .env file location
# .env must be in the same directory as docker-compose.yml

Fix 7: COMPOSE_FILE Environment Variable

Set override files permanently via environment variable instead of -f flags:

# Set in shell (current session)
export COMPOSE_FILE=docker-compose.yml:docker-compose.override.yml

# Set in .env file (persists for the project)
echo "COMPOSE_FILE=docker-compose.yml:docker-compose.override.yml" >> .env

# Now plain 'docker compose up' loads both files
docker compose up

Different separators by OS:

  • Linux/Mac: colon : separator
  • Windows: semicolon ; separator
# Windows
COMPOSE_FILE=docker-compose.yml;docker-compose.override.yml

Fix 8: Catch Silent Config Drift in CI

The most dangerous form of this bug is the one no one notices. Your dev environment is supposed to mount ./src, but it does not, and tests still pass because the container has stale source code baked in from the last image build. Add a CI step that asserts the merged config matches expectations.

# In CI, dump the merged config and check critical fields
docker compose -f docker-compose.yml -f docker-compose.override.yml config > merged.yml

# Assert that the dev volume mount is present
grep -q "./src:/app/src" merged.yml || {
  echo "FAIL: source volume mount missing from dev compose config"
  exit 1
}

# Assert that production has the right replica count
docker compose -f docker-compose.yml -f docker-compose.prod.yml config | \
  grep -q "replicas: 3" || {
  echo "FAIL: production replica count is not 3"
  exit 1
}

Snapshot the merged config in git. A subtler approach: commit a compose.merged.yml file generated by docker compose config, and re-generate it in CI. If the regenerated file diverges from the committed one, the override has changed and the diff is visible in code review. This catches accidental drift (someone changed an override locally and forgot to update the prod variant).

Lock environment selection. Add a .envrc (direnv) or .tool-versions file that exports the correct COMPOSE_FILE for the project so developers cannot accidentally inherit a stale value from their shell:

# .envrc — checked into git
export COMPOSE_FILE=docker-compose.yml:docker-compose.override.yml

The production incident lens. Override-file bugs almost never page on-call because they break the development or test environment, not production. But the cost compounds: developers waste hours chasing “works on my machine” issues, CI runs against a config that differs from local, and bugs introduced under the wrong override sneak past testing and land in production. Treat config drift as a quiet outage of the test environment itself. The blast radius is everyone on the team, the mean-time-to-detect is days or weeks, and the recovery is “everyone deletes node_modules and runs docker compose down -v.”

Still Not Working?

Docker Compose v1 vs v2 differencesdocker-compose (v1) and docker compose (v2) handle some edge cases differently. If you’re using docker-compose (with hyphen), verify it’s finding the override file:

docker-compose --verbose config 2>&1 | grep -i "override\|reading"

Project name mismatch — if you run Docker Compose from different directories or with different project names, it may not recognize existing services. Use COMPOSE_PROJECT_NAME or the -p flag consistently.

Override file encoding — YAML is sensitive to indentation. A tab instead of spaces, or incorrect indentation level, causes the file to parse incorrectly (or silently fail to merge a section). Use docker compose config to confirm the merged output looks right.

Profiles activate or deactivate the override — Compose profiles can keep services out of the merge if their profile is not active. If a service exists in the override but not in docker compose config output, check whether the service has a profiles: key and whether the profile is enabled via --profile or COMPOSE_PROFILES.

Anchors and aliases not expanding — YAML &anchor / *alias references work inside a single file but not across two merged files. If you anchor in docker-compose.yml and try to reference it in docker-compose.override.yml, the alias is undefined. Inline the value instead.

Inherited overrides from parent directory — older versions of Docker Compose searched upward for compose files. v2 does not, but some IDE integrations still do. If a developer’s editor is launching docker compose from ~/projects/ rather than ~/projects/myapp/, the override file in the project directory is never read.

For related Docker issues, see Fix: Docker Compose depends_on Not Working, Fix: Docker Compose Networking Not Working, Fix: Docker Compose env Not Loaded, and Fix: Docker Compose Healthcheck Not Working.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles