Compose Watch

Compose Watch for Live Development

Bind Mounts got a live edit loop by bind-mounting the source and running node --watch, at the cost of running a different container from the one you ship. Compose 514 Watch, generally available since Compose 2.22 (September 2023), keeps the real image and pushes changes into it. Each rule under develop.watch maps a host path to an action: sync copies the file into the running container, sync+restart also restarts it, sync+exec runs a command after copying and restart only restarts (both Compose 2.32), and rebuild builds a new image and replaces the container. BookNest's API loads app.js once at startup, and a changed lockfile means new dependencies:

compose.yaml: watch rules for the APIYAML
    develop:
      watch:
        - action: sync+restart
          path: ./app.js
          target: /app/app.js
        - action: rebuild
          path: package-lock.json

docker compose up --watch starts and watches in one terminal; watch --no-up attaches to a running stack:

Editing app.js while Compose Watch runsJavaScript
docker compose watch --no-up > ../watch.log 2>&1 & sleep 3
sed -i "s/{ status: 'ok' }/{ status: 'ok', watched: true }/" app.js
sleep 6; curl -s localhost:33000/health; echo
cat ../watch.log; kill %1; git checkout -q app.js
Output
{"status":"ok","watched":true}
Watch enabled
Syncing service "api" after 1 changes were detected
 Container l3-booknest-api-1 Restarting
 Container l3-booknest-api-1 Started
service(s) ["api"] restarted

Watch applies the .dockerignore rules, so node_modules and .env never travel, and ignores unmatched paths: an edit to server.js waits for the next build. Compose 2.24 dropped the old rule that the container's user must be able to write the target; here the root-owned /app/app.js was replaced in a container running as UID 1000.