Docker and Kubernetes course menu
Docker Compose for Development: Live Reload and Overrides
Set up a development environment with Compose: bind mounts and live reload, protecting node_modules, Compose watch, override files, and profiles for optional services.
On this page
In production, code is built into the image. In development, you want to save a file and see the change at once. Compose handles both from the same project.
Live reload with a bind mount#
Here a Node.js server runs with --watch, and the project folder is mounted into the container:
mkdir api
cd api
cat > server.js <<'EOF'
import { createServer } from "node:http";
createServer((req, res) => res.end("Version 1\n")).listen(3000);
EOF
echo '{ "type": "module" }' > package.json
cat > compose.yaml <<'EOF'
services:
api:
image: node:24-alpine
working_dir: /app
command: node --watch server.js
ports:
- "3000:3000"
volumes:
- .:/app
EOF
docker compose up -d --quiet-pull > /dev/null 2>&1
sleep 3
curl -s http://localhost:3000
sed -i 's/Version 1/Version 2/' server.js
sleep 3
curl -s http://localhost:3000
docker compose down > /dev/null 2>&1Version 1
Version 2No rebuild was needed. For Python, use flask --debug run or uvicorn --reload in the same way.
Protecting node_modules#
Mounting your project over /app hides any node_modules that the image installed. The usual fix is an extra volume on that one folder, which covers the bind mount at that path:
services:
web:
build: .
volumes:
- .:/app
- /app/node_modulesCompose watch#
docker compose watch is a built-in alternative to bind mounts. It syncs changed files into the container, and rebuilds when dependencies change:
services:
web:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: package.jsondocker compose watchIt works well on Windows and macOS, where bind mounts can be slow.
Override files#
Keep production settings in compose.yaml, and development extras in compose.override.yaml. Compose merges that file automatically:
cat > compose.yaml <<'EOF'
services:
api:
image: node:24-alpine
environment:
APP_ENV: production
EOF
cat > compose.override.yaml <<'EOF'
services:
api:
environment:
APP_ENV: development
DEBUG: "true"
ports:
- "3000:3000"
EOF
docker compose config | grep -E 'APP_ENV|DEBUG|published'
echo ---
docker compose -f compose.yaml config | grep -E 'APP_ENV|DEBUG|published' APP_ENV: development
DEBUG: "true"
published: "3000"
---
APP_ENV: productiondocker compose config prints the final, merged result. With -f, Compose uses only the files you name, which is how you ignore the override file in production.
Profiles#
Mark optional services with a profile, and they start only when asked for:
cat > compose.yaml <<'EOF'
services:
api:
image: redis:8.6-alpine
debug-tools:
image: redis:8.6-alpine
profiles: [debug]
EOF
rm compose.override.yaml
docker compose config --services
echo ---
docker compose --profile debug config --services | sortapi
---
api
debug-toolsOne-off commands#
docker compose run starts a temporary container, which suits tests and migrations:
docker compose run --rm api redis-cli --version 2>&1 | grep '^redis-cli' | cut -d' ' -f1,2redis-cli 8.6.8Typical uses are these:
docker compose run --rm api npm test
docker compose run --rm api python manage.py migrateA good team setup#
- A
compose.yamlthat starts everything with no extra steps. - A
.env.examplethat people can copy to.env. - Seed data, so that the app is useful at once.
- A README with one command:
docker compose up.
Common mistakes#
Practice#
Practice exercise
Without starting anything, use docker compose config --services to check that a file with services web and db is valid, and print how many services it has.
Show solution
cat > compose.yaml <<'EOF'
services:
web:
image: redis:8.6-alpine
db:
image: redis:8.6-alpine
EOF
docker compose config --services | wc -l2Key takeaway#
Finished this lesson?
Related lessons
Recommended Docker and Kubernetes resources
- Docker Deep Dive by Nigel Poulton
A practical guide to how Docker works, for readers who have finished the basics.
Some links are affiliate links. If you buy through them, Laviyx Learn may earn a commission at no extra cost to you. As an Amazon Associate, we earn from qualifying purchases.