TiloBox
Back to directory
Watchexec project preview

Watchexec

A command runner that watches files and restarts or invokes commands when matching paths change.

LicenseApache-2.0
GitHub stars7.1k
Last commit1 weeks ago
Tags7 topics
CliFile WatcherRustSelf HostedOpen SourceBuild ToolsDeveloper Tools
Overview

Why consider Watchexec?

watchexec is a simple, standalone, language-agnostic CLI tool that watches a path and automatically executes a command whenever it detects file modifications. Written in Rust, it runs on Linux, macOS, and Windows, uses kernel-level filesystem event APIs for efficiency, coalesces rapid bursts of changes with debouncing, respects `.gitignore`/`.ignore` files, exposes changed paths via environment variables, and can restart long-running processes on each change — all without requiring any language runtime or cryptic `xargs` pipelines.

Guided learning

Learn Watchexec by building

Practical setup notes, real use cases, and copy-ready examples in one focused guide.

5 min read 12 sections
In this guide12 sections

watchexec — Run Commands Automatically on File Changes

watchexec is a simple, standalone tool that watches a path and runs a command whenever it detects file modifications. It is written in Rust, ships as a single binary with no required runtime, and works on Linux, macOS, and Windows.

Why watchexec?

Every developer repeats the same cycle: edit a file, switch to a terminal, run a build or test command, switch back. watchexec eliminates the manual switch by acting as an automated trigger between your editor and your toolchain.

Key properties verified from the source:

  • No language runtime required — a single binary is all you need.
  • Cross-platform — runs on Linux, Mac, Windows, and more using efficient kernel-level event APIs.
  • Smart filtering — automatically respects .gitignore and .ignore files, so build artifacts and hidden files are silently excluded by default.
  • Debouncing — multiple filesystem events caused by editors that use swap/backup files during saving are coalesced into a single trigger.
  • Process groups — uses process groups to keep hold of forking programs, so child processes are cleanly managed.
  • Environment variables — exposes the exact paths that changed via $WATCHEXEC_WRITTEN_PATH, $WATCHEXEC_CREATED_PATH, $WATCHEXEC_REMOVED_PATH, $WATCHEXEC_RENAMED_PATH, $WATCHEXEC_META_CHANGED_PATH, and $WATCHEXEC_OTHERWISE_CHANGED_PATH, enabling advanced scripting.
  • --emit-events — event emission can be disabled with --emit-events=none or switched to JSON via --emit-events=json-stdio.

Installation

watchexec is packaged for most major platforms. A few quick options:

bash
1# macOS / Linux via Homebrew
2brew install watchexec
3
4# Arch Linux
5pacman -S watchexec
6
7# Alpine Linux
8apk add watchexec
9
10# Rust / Cargo
11cargo install watchexec-cli
12
13# Debian / Ubuntu (using the .deb from GitHub Releases)
14dpkg -i watchexec-*.deb

Pre-built binaries (.tar.xz, .deb, .rpm) are available on the GitHub Releases page.

Quick-Start Examples

The following examples are taken directly from the official README and CLI documentation.

Watch by file extension and run a build

bash
1# Watch all JavaScript, CSS and HTML files in the current directory
2# and all subdirectories for changes, running `npm run build` when a change is detected:
3$ watchexec -e js,css,html npm run build

Restart a long-running server on changes

bash
1# Call/restart `python server.py` when any Python file
2# in the current directory (and all subdirectories) changes:
3$ watchexec -r -e py -- python server.py

Ignore a directory

bash
1# Call `make test` when any file changes, except everything below `target`:
2$ watchexec -i "target/**" make test

Send a custom stop signal

bash
1# Restart `my_server`, sending SIGKILL to stop it:
2$ watchexec -r --stop-signal SIGKILL my_server

Watch specific directories

bash
1# Watch lib and src directories for changes, rebuilding each time:
2$ watchexec -w lib -w src make

How Event Filtering Works

watchexec applies filters in a strict order (documented in the CLI source):

  1. Internal prioritisation — signals (SIGINT/SIGTERM) are always processed first.
  2. File event kind — controlled by --fs-events.
  3. Explicit watch paths — files/dirs passed with -w.
  4. Ignores--ignore flags and .gitignore / .ignore files.
  5. Filters — including --exts and glob patterns.
  6. Filter programs — external programs used as custom filters.

Because .gitignore is loaded by default, your build artefacts directory will never accidentally trigger a rebuild.

Environment Variables Injected into Commands

watchexec sets $WATCHEXEC_COMMON_PATH to the longest common path of all changed paths. Each event-kind variable below should be prepended with that common path to obtain the full path. Multiple paths within one variable are separated by : on Unix and ; on Windows — matching the platform PATH convention.

VariableEvent kind
$WATCHEXEC_CREATED_PATHfiles/folders were created
$WATCHEXEC_REMOVED_PATHfiles/folders were removed
$WATCHEXEC_RENAMED_PATHfiles/folders were renamed
$WATCHEXEC_WRITTEN_PATHfiles/folders were modified
$WATCHEXEC_META_CHANGED_PATHfiles/folders' metadata were modified
$WATCHEXEC_OTHERWISE_CHANGED_PATHevery other kind of event

Using watchexec as a Rust Library

watchexec also ships a first-party Rust library crate (watchexec) that powers the CLI. It is licensed under Apache 2.0. Here is the minimal setup taken from the library README:

rust
1use watchexec::{
2 command::{Command, Program, Shell},
3 Watchexec,
4};
5use watchexec_events::{Event, Priority};
6
7#[tokio::main]
8async fn main() -> miette::Result<()> {
9 let wx = Watchexec::new(|mut action| {
10 let (_, job) = action.create_job(std::sync::Arc::new(Command {
11 program: Program::Shell {
12 shell: Shell::new("bash"),
13 command: "echo 'Hello world'".into(),
14 args: Vec::new(),
15 },
16 options: Default::default(),
17 }));
18 job.start();
19 action
20 })?;
21
22 let main = wx.main();
23 wx.send_event(Event::default(), Priority::Urgent).await.unwrap();
24 main.await.unwrap()?;
25 Ok(())
26}

API docs live at docs.rs/watchexec.

Tips and Troubleshooting

  • Network shares / WSL: Native filesystem events may not fire. Add --poll to fall back to polling.
  • Shell expansion: If your command contains globs, quote them so the shell does not expand them before handing them to watchexec. Compare watchexec echo src/*.rs vs watchexec echo 'src/*.rs'.
  • Argfile support: Pass @argfile as the first argument to load flags from a file (one argument per line), useful for complex configurations.
  • Desktop notifications: Use --notify (where supported) to receive a desktop notification on command start and end.
  • Clear screen: Add -c to clear the terminal before each execution, keeping output readable.

Related tools

More options with a similar category or technology profile.

Watchexec FAQs

Watchexec is listed as a Developer Tools tool on TiloBox. Review the overview, features, and official documentation on this page to decide whether it solves your specific workflow.

Start with the project's GitHub repository and official website for supported installation and deployment instructions. Test the setup with representative data or a small project before rolling it out more widely.

Watchexec is listed under the Apache-2.0 license. Read the complete license text and the project's notices before using, modifying, or distributing the software.

Production readiness depends on your requirements. Review maintenance activity, security practices, documentation, backup and upgrade procedures, and compatibility with your stack; then validate it in a non-production environment.

Watchexec is listed as an alternative to Nodemon. Compare the core workflow, deployment model, integrations, and licensing against your must-have requirements before switching.