watchexec: Usage, Options & Common CI Errors
watchexec re-runs a command whenever watched files change.
watchexec is a file-watcher for local dev loops. The CI hazard is obvious once stated: it is a long-running watcher, so invoking it in a pipeline hangs the job until timeout.
What it does
watchexec monitors a directory tree for changes and runs (or restarts) a command in response. It respects .gitignore by default and can filter by extension or path, making it a fast local feedback loop.
Common usage
watchexec -- cargo test
watchexec -e ts,tsx -- npm run build
watchexec -w src -- ./run.sh # watch a specific dir
watchexec -r -- node server.js # restart on change
watchexec --exts py --debounce 500ms -- pytestOptions
| Flag | What it does |
|---|---|
| -e / --exts <list> | Only react to these file extensions |
| -w / --watch <path> | Watch a specific path (repeatable) |
| -r / --restart | Restart the command instead of waiting |
| --debounce <dur> | Coalesce rapid changes into one run |
| -i / --ignore <glob> | Ignore matching paths |
| -1 / --once | Run once then exit (no watching) |
Common errors in CI
watchexec never exits on its own - it watches forever - so a CI step that calls it stalls until the job timeout kills it. It is a dev tool: do not put a bare watchexec in a pipeline. If you only want to run the command once, use the underlying command directly (or watchexec -1). On headless runners with no inotify capacity you may see "too many open files" / "inotify watch limit reached"; raise fs.inotify.max_user_watches.