docker compose watch, and the bind mount it replaces

A bind mount of the whole project into the container is the standard local setup and is the reason the stack is slow on some machines.

services:
  php:
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: ./composer.lock

# sync copies changed files in; rebuild rebuilds the image
# when a dependency file changes.

The difference from a bind mount is that the container filesystem is real rather than a shared-mount translation layer, which on macOS and Windows is where the time goes — a test suite that took 94 seconds over a bind mount ran in 31. The cost is that the sync is one-directional: anything the container writes into a watched path is not reflected back, so generated files need an explicit exception or a separate volume.