# watchexec — Run Commands When Files Change, with Smart Defaults > watchexec watches a directory tree and runs a command when anything changes. Cross-platform, respects .gitignore, debounces, restarts long-running processes — the swiss-army knife of file-watching. ## Install Save in your project root: # watchexec — Run Commands on File Changes ## Quick Use ```bash # macOS brew install watchexec # Cargo cargo install watchexec-cli --locked # Run tests whenever any file changes watchexec -- cargo test # Only watch specific file types watchexec -e ts,tsx -- npm run build # Restart a long-running process (like a server) watchexec -r -- ./my-server # Clear screen between runs watchexec -c -- pytest ``` ## Introduction watchexec is the "watch these files, run this command" tool for everyone who's ever hacked together the same bash script with `inotifywait` or `fswatch`. Written in Rust, it works identically on macOS, Linux, and Windows, respects `.gitignore` by default, debounces rapid saves, and can restart processes on change (sending proper SIGTERM then SIGKILL). With over 7,000 GitHub stars, watchexec powers many developer tools' "watch mode" under the hood (including `cargo-watch` built directly on top of it). If you've ever wanted a reliable file-watcher, this is the one. ## What watchexec Does watchexec monitors directory trees with native filesystem events (FSEvents on macOS, inotify on Linux, ReadDirectoryChangesW on Windows). When events arrive, it debounces them (coalesce bursts), applies include/exclude filters, and runs a shell command or replaces the running process. ## Architecture Overview ``` [Filesystem] | [Native watcher: FSEvents / inotify / ReadDirectoryChangesW] | [Event Stream] batched + debounced (100ms default) | [Filter Layer] --exts / --filter-file / .gitignore / --ignore | [Exec Layer] run command, or restart (-r) signal: SIGTERM -> SIGKILL after grace period clear screen (-c), emit bell (-N), notify (-n) ``` ## Self-Hosting & Configuration ```bash # Debounce changes over 500ms, ignore node_modules watchexec --debounce 500 -i node_modules -- npm run build # Multiple commands on change (shell) watchexec -- "npm run lint && npm test" # Restart a server, send SIGINT instead of SIGTERM watchexec -r --signal SIGINT -- node server.js # Watch only Go files, clear screen, send bell on run watchexec -e go -c -N -- go test ./... # Run once immediately then wait for changes watchexec --on-busy-update=restart -w . --project-origin . -- ./dev.sh # Using an environment file to pass changed file names watchexec --emit-events-to=environment -- bash -c 'echo "$WATCHEXEC_WRITTEN_PATH changed"' ``` ```bash # Common language-specific workflows watchexec -e py -- pytest watchexec -e go -- go test ./... watchexec -e rs -- cargo test watchexec -e ts,tsx -- bun run build watchexec -e md -- mdbook build # With pre-commit-style hooks watchexec -e py -- "ruff check . && pytest -q" ``` ## Key Features - **Cross-platform** — same flags work on macOS, Linux, Windows - **.gitignore aware** — skip ignored files by default - **Debouncing** — coalesce bursts of saves into one run - **Process restart** — `-r` kills and restarts long-running servers cleanly - **Extension filters** — `-e go,mod,sum` common shorthand - **Clear / bell / notify** — UX niceties built-in - **Event metadata** — pass changed paths to the command via env vars - **Library + CLI** — Rust library used by cargo-watch, lefthook, and others ## Comparison with Similar Tools | Feature | watchexec | entr | fswatch | inotifywait | nodemon | |---|---|---|---|---|---| | Language | Rust | C | C++ | C | Node | | Cross-platform | Yes | Unix | Unix + partial Win | Linux only | Yes | | Debouncing | Built-in | Manual | Manual | Manual | Built-in | | .gitignore | Built-in | Manual | Manual | Manual | Built-in | | Restart on change | Yes (-r) | Manual | Manual | Manual | Yes (focus) | | Best For | Universal watcher | Unix hackers | Bash + fsevents | Linux-only workflows | Node-specific | ## FAQ **Q: watchexec vs entr?** A: watchexec is cross-platform, .gitignore-aware, debounced by default. entr is simpler (just reads file list from stdin) but Unix-only. watchexec is more robust for cross-platform dev teams. **Q: Does it stop on errors?** A: By default no — it keeps waiting for the next change. Combine with shell: `watchexec -- "cmd || true"` to suppress failure, or use `--on-busy-update=signal` for more control. **Q: Can I pass the changed file name to my command?** A: Yes — `--emit-events-to=environment` sets `WATCHEXEC_WRITTEN_PATH`, `WATCHEXEC_CREATED_PATH`, etc., in the command's env. Or `--emit-events-to=stdio` to pipe events as JSON. **Q: Does it work over network filesystems?** A: Partially. NFS and SMB may miss events (they depend on the filesystem driver). For critical workflows, watch a local mount or poll with `--poll=200ms`. ## Sources - GitHub: https://github.com/watchexec/watchexec - License: Apache-2.0 --- Source: https://tokrepo.com/en/workflows/8f4872e1-3814-11f1-9bc6-00163e2b0d79 Author: AI Open Source