Compose for dev cheatsheet.
Dev override
# compose.yml (prod-ish baseline)
services:
web:
build: .
image: myapp:latest
environment:
DATABASE_URL: postgres://postgres:x@db:5432/myapp
# compose.override.yml (auto-merged in dev)
services:
web:
volumes:
- .:/app
- /app/node_modules
environment:
DEBUG: "1"
command: npm run dev
ports: ["3000:3000"]
docker compose up # uses both files
docker compose -f compose.yml -f compose.prod.yml up # for prod
Hot reload
services:
web:
volumes:
- .:/app
- /app/node_modules # preserve image's
command: npm run dev # uses --watch
For Python:
services:
web:
volumes: [".:/app"]
command: uvicorn main:app --reload --host 0.0.0.0
Anonymous volumes for node_modules
volumes:
- .:/app # bind source
- /app/node_modules # anonymous; hides bind for this path
Otherwise host’s node_modules (or absence) overrides image’s.
watch (compose v2.22+)
services:
web:
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: ./package.json
docker compose watch
Replaces bind mount with file sync. Better cross-platform performance.
Build only on demand
services:
web:
image: myapp:dev
build:
context: .
target: dev
docker compose build # rebuild image
docker compose up # uses cached unless built
Multiple environments
docker compose --profile dev up
docker compose --profile prod -f compose.yml -f compose.prod.yml up
services:
web:
profiles: [dev, prod]
mailhog:
image: mailhog/mailhog
profiles: [dev]
prometheus:
image: prom/prometheus
profiles: [monitoring]
.env file
# .env (auto-loaded)
COMPOSE_PROJECT_NAME=myapp
TAG=v1
DATABASE_URL=postgres://postgres:x@db:5432/myapp
services:
web:
image: myapp:${TAG}
env_file: .env
Helpful dev containers
services:
db:
image: postgres:16
environment: { POSTGRES_PASSWORD: x }
ports: ["5432:5432"] # expose for local connections
volumes: [pg_data:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
ports: ["6379:6379"]
mailhog:
image: mailhog/mailhog
ports:
- "1025:1025" # SMTP
- "8025:8025" # UI
adminer:
image: adminer
ports: ["8080:8080"]
volumes:
pg_data:
Devcontainer (VS Code)
.devcontainer/devcontainer.json:
{
"name": "myapp",
"dockerComposeFile": "../compose.yml",
"service": "web",
"workspaceFolder": "/app",
"customizations": {
"vscode": {
"extensions": ["ms-python.python", "esbenp.prettier-vscode"]
}
},
"postCreateCommand": "npm install"
}
Open in VS Code → “Reopen in container.”
Debugger ports
services:
web:
ports:
- "3000:3000"
- "9229:9229" # Node inspector
node --inspect=0.0.0.0:9229 server.js
Attach VS Code debugger to localhost:9229.
For Python (debugpy):
import debugpy
debugpy.listen(("0.0.0.0", 5678))
ports: ["5678:5678"]
docker compose exec for tooling
docker compose exec web npm test
docker compose exec web python manage.py migrate
docker compose exec db psql -U postgres myapp
Service-specific commands
services:
shell:
image: myapp:latest
profiles: [tools]
command: bash
tty: true
stdin_open: true
docker compose run --rm shell
Use compose for tests
services:
test:
build: .
command: pytest
depends_on:
db: { condition: service_healthy }
docker compose run --rm test
docker compose down -v # cleanup
Hot reload across multiple services
services:
api:
volumes: [".:/app"]
command: uvicorn main:app --reload
worker:
volumes: [".:/app"]
command: celery -A config worker -l info --autoreload
Code changes hit both.
Speed tips on Mac/Windows
- Use
:cachedconsistency flag for big bind mounts. - Use named volumes for
node_modules,.venv,target/. - Use
docker compose watch(sync) instead of bind. - OrbStack / Colima > Docker Desktop.
Common mistakes
- Bind-mounting
node_modulesfrom host → mismatched native modules. - Production image used unchanged in dev — no hot reload.
- Forgetting
tty: truefor interactive containers. - Ports conflict with host services.
command:in compose overriding CMD — confusion about which runs.
Read this next
If you want my dev compose + devcontainer setup, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .