Fix: docker-compose.override.yml Not Working — Override File Ignored or Not Merged
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 ignoredOr an explicit -f flag stops the override from loading:
docker compose -f docker-compose.yml up
# Only docker-compose.yml loaded — override.yml skipped entirelyOr 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-loadingIn 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(notdocker-compose.override.yaml, notoverride.yml). The.ymlextension 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. -fflag disables auto-loading — as soon as you use-fto specify any file, Docker Compose stops auto-loading and only uses the files you explicitly listed.- Docker Compose v1 vs v2 —
docker-compose(v1, Python) vsdocker compose(v2, Go plugin) have minor behavioral differences. Some older setups usedocker-compose.ymlonly 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 loadedCheck the current directory:
pwd
ls docker-compose*.yml
# Must run docker compose from the directory containing both files
# Not from a parent or child directoryFix 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,environmentarrays 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 \
upAdd 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 --buildFix 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: 512MFix 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: 3Remove 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 devFix 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 configCheck 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.ymlFix 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 upDifferent separators by OS:
- Linux/Mac: colon
:separator - Windows: semicolon
;separator
# Windows
COMPOSE_FILE=docker-compose.yml;docker-compose.override.ymlFix 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.ymlThe 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 differences — docker-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.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Docker Secrets Not Working — BuildKit --secret Not Mounting, Compose Secrets Undefined, or Secret Leaking into Image
How to fix Docker secrets — BuildKit secret mounts in Dockerfile, docker-compose secrets config, runtime vs build-time secrets, environment variable alternatives, and verifying secrets don't leak into image layers.
Fix: Docker Compose Healthcheck Not Working — depends_on Not Waiting or Always Unhealthy
How to fix Docker Compose healthcheck issues — depends_on condition service_healthy, healthcheck command syntax, start_period, custom health scripts, and debugging unhealthy containers.
Fix: Docker Build ARG Not Available — ENV Variables Missing at Runtime
How to fix Docker ARG and ENV variable issues — build-time vs runtime scope, ARG before FROM, multi-stage build variable passing, secret handling, and .env file patterns.
Fix: Docker HEALTHCHECK Failing — Container Marked Unhealthy Despite Running
How to fix Docker HEALTHCHECK failures — command syntax, curl vs wget availability, start period, interval tuning, health check in docker-compose, and debugging unhealthy containers.