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.
What it is
watchexec is a cross-platform file watcher that runs a command whenever files in a directory change. Written in Rust, it provides smart defaults: respecting .gitignore, debouncing rapid changes, and restarting long-running processes automatically.
watchexec is ideal for developers who want instant feedback loops during development -- rerunning tests, rebuilding projects, or restarting servers on save without configuring complex watch tools.
How it saves time or tokens
watchexec eliminates the manual cycle of saving a file, switching to a terminal, and rerunning a command. It handles the edge cases that simple watch scripts miss: debouncing multiple rapid file saves into a single run, ignoring build artifacts via .gitignore, and cleanly restarting long-running processes rather than spawning duplicates.
How to use
- Install watchexec:
# macOS
brew install watchexec
# Rust
cargo install watchexec-cli --locked
- Run tests on any file change:
watchexec -- cargo test
- Watch specific file types:
watchexec -e ts,tsx -- npm run build
- Restart a server on changes:
watchexec -r -- ./my-server
Example
# Clear screen between runs and run pytest
watchexec -c -- pytest
# Watch only src/ directory, restart on change
watchexec -w src -r -- python app.py
# Filter by extension and ignore patterns
watchexec -e py -i '__pycache__' -- python -m myapp
# Run with shell features (pipes, redirects)
watchexec -- 'cargo build 2>&1 | head -20'
Related on TokRepo
- Automation tools — file watching and workflow automation
- AI coding tools — development productivity tools
Common pitfalls
- Forgetting the
--separator between watchexec flags and the command to run - Not using
-rfor long-running processes, which causes multiple instances to stack up - Watching too broad a directory tree, triggering runs from build output changes
Frequently Asked Questions
watchexec is language-agnostic and runs any command, while nodemon is focused on Node.js applications. watchexec is written in Rust with better performance, supports .gitignore natively, and handles process restart more reliably.
Yes. watchexec reads .gitignore files by default and excludes matched paths from triggering events. You can disable this with the --no-vcs-ignore flag if needed.
Yes. Use the -r flag to send a termination signal to the running process and restart it when files change. This is the correct mode for development servers, as it avoids spawning duplicate processes.
watchexec runs on Linux, macOS, and Windows. It uses native file system events (inotify, FSEvents, ReadDirectoryChanges) for efficient low-latency watching on each platform.
watchexec waits a short period after detecting a change before running the command. If more changes arrive during that window, it resets the timer. This prevents running the command multiple times during a batch save operation.
Citations (3)
- watchexec GitHub— watchexec is a cross-platform file watcher written in Rust
- watchexec Documentation— Smart defaults including .gitignore support and debouncing
- Rust CLI Working Group— Rust CLI tools for developer productivity
Related on TokRepo
Discussion
Related Assets
Conda — Cross-Platform Package and Environment Manager
Install, update, and manage packages and isolated environments for Python, R, C/C++, and hundreds of other languages from a single tool.
Sphinx — Python Documentation Generator
Generate professional documentation from reStructuredText and Markdown with cross-references, API autodoc, and multiple output formats.
Neutralinojs — Lightweight Cross-Platform Desktop Apps
Build desktop applications with HTML, CSS, and JavaScript using a tiny native runtime instead of bundling Chromium.