Docker Compose — Docker Compose FAQ
Answers to the most frequently asked questions about Docker Compose.
General
What is the difference between Docker Compose V1 and V2?
Docker Compose V1 was a Python-based tool installed as docker-compose (with a hyphen). Docker Compose V2 is a Go-based plugin installed as docker compose (with a space). V2 is the current standard and is included with Docker Desktop.
# V1 (deprecated)
docker-compose up -d
# V2 (current)
docker compose up -d
Recommendation: Always use V2. Docker officially deprecated V1 in April 2023.
Should I use docker-compose.yml or compose.yml?
Both work, but compose.yml is the modern convention. Docker Compose V2 looks for files in this order:
compose.yamlcompose.ymldocker-compose.yamldocker-compose.yml
Can I use Compose in production?
Yes, with caveats. Compose works well for single-host production deployments. For multi-host setups, consider Kubernetes or Docker Swarm. Use docker compose up -d with restart policies for reliable production operation.
Configuration
How do I use environment variables in compose.yml?
Three ways:
services:
app:
# 1. Direct value
environment:
DB_HOST: postgres
# 2. Variable substitution from .env or shell
environment:
DB_HOST: ${DB_HOST}
# 3. env_file
env_file:
- .env
How do I use multiple Compose files?
# Merge files (later files override earlier)
docker compose -f compose.yml -f compose.prod.yml up -d
# Or set COMPOSE_FILE environment variable
export COMPOSE_FILE=compose.yml:compose.prod.yml
docker compose up -d
How do I share compose.yml variables between services?
Use YAML anchors:
x-common-env: &common-env
LOG_LEVEL: info
TZ: UTC
services:
api:
environment:
<<: *common-env
PORT: 3000
worker:
environment:
<<: *common-env
QUEUE: default
Networking
Can services communicate by name?
Yes. Compose creates a default network where services can reach each other using their service name as a hostname:
services:
api:
environment:
DB_HOST: postgres # ← this resolves to the postgres container
postgres:
image: postgres:16
How do I expose a service only to other containers?
Use expose instead of ports:
services:
db:
expose:
- "5432" # accessible to other containers, not from host
Volumes
What is the difference between named volumes and bind mounts?
services:
app:
volumes:
- db-data:/var/lib/data # Named volume — Docker manages storage
- ./config:/etc/app/config # Bind mount — maps a host directory
volumes:
db-data: # Named volume declaration
Named volumes persist across container restarts and are managed by Docker. Bind mounts map a specific host path into the container.
Does docker compose down delete my data?
No — docker compose down removes containers and networks but preserves volumes. To also delete volumes:
docker compose down -v # WARNING: deletes all named volumes
Troubleshooting
Why is my service not starting?
Check in this order:
docker compose ps— Is the container running?docker compose logs <service>— Any error messages?docker compose config— Is the YAML valid?- Check
depends_onwith health checks — Are dependencies ready?
Why can one service not connect to another?
Common causes:
- Wrong hostname — Use the service name, not
localhost - Different networks — Both services must be on the same network
- Service not ready — Use
depends_onwithcondition: service_healthy - Wrong port — Use the container port, not the host port
How do I reset everything?
# Nuclear option — remove everything
docker compose down -v --rmi all --remove-orphans
# Verify nothing is left
docker compose ps -a
Performance
How do I limit container resources?
services:
app:
deploy:
resources:
limits:
cpus: "0.5"
memory: 256M
reservations:
cpus: "0.25"
memory: 128M
How do I speed up builds?
- Use multi-stage builds to reduce image size
- Order Dockerfile layers — put
COPY package*.jsonbeforeCOPY . . - Use
.dockerignoreto exclude unnecessary files - Use BuildKit —
DOCKER_BUILDKIT=1 docker compose build
Best Practices
Should every project have a compose.yml?
Yes. Even a single-container app benefits from a compose.yml:
- Documents the runtime configuration
- Makes onboarding easier (
docker compose upand done) - Enables easy addition of databases, caches, etc.
How should I organize multiple compose files?
project/
├── compose.yml # Base configuration
├── compose.dev.yml # Development overrides
├── compose.prod.yml # Production overrides
├── compose.test.yml # Test-specific services
└── .env # Default environment variables
Should I pin image versions?
Always. Never use :latest in production:
# Bad
image: postgres:latest
# Good
image: postgres:16.1-alpine
Pinning versions prevents unexpected breakage when images are updated.