CLI tool
watchexec/watchexec avatar
watchexec/watchexec

watchexec: run a command whenever a file changes, without a language runtime

Project brief: Executes commands in response to file modifications. watchexec is a simple, standalone tool that watches a path and runs a command whenever it detects modifications.

7,189 stars202 forksRustApache-2.0

At a glance

What is it?
watchexec is a standalone Rust binary that watches a path and reruns a command on modification. It is easy to install and easy to misuse on long-running servers, and the README leaves several operational questions open.
Who is it for?
Adopt watchexec if you want a language-agnostic file watcher installed once and reused across projects: install it with cargo install --locked watchexec-cli or your package manager, then start with watchexec -e js,css,html npm run build. Skip it if you need a persistent service that survives reboots, or if you want a build system that understands dependency graphs; watchexec only knows that something under the watched path changed.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem watchexec solves, and who ends up using it

The README opens with the observation that "software development often involves running the same commands over and over", and watchexec exists to remove the manual repetition. You point it at a path, it watches that path and all subdirectories, and it runs a command when something changes. The README lists three example use cases: automatically run unit tests, run linters or syntax checkers, and rebuild artifacts.

The audience is anyone whose edit-run loop is dominated by retyping the same shell command. Because watchexec ships as a compiled binary with no language runtime, it is not tied to any particular language or ecosystem. A Rust developer, a Python developer and a front-end developer can all install the same tool and use the same flags. That is the main reason to pick it over a watcher bundled inside a framework: the tool outlives the project's language choice.

The README also positions watchexec as a library, not only a CLI. The workspace contains crates/lib, crates/events, crates/signals and crates/supervisor, and the README describes the library as a way "to create more specialised watchexec-powered tools". Downstreams listed in the README include cargo lambda, devenv.sh, dotter and ghciwatch. If you are building a specialised watcher for one ecosystem, the library is the relevant entry point; if you just want to stop retyping commands, the CLI is.

How the watcher is put together: crates, ignore files and process groups

The repository is a Cargo workspace. The Cargo.toml lists members including crates/lib, crates/cli, crates/events, crates/signals, crates/supervisor, crates/filterer/globset, crates/filterer/ignore, crates/bosion, crates/ignore-files and crates/project-origins. That layout tells you the design is split along responsibilities rather than shipped as one monolith: event types live in one crate, signal types in another, and the process lifecycle manager is separated out as watchexec-supervisor, which the README calls "the exec part of watchexec".

Two behaviours in the README are worth understanding before you run anything. First, watchexec "coalesces multiple filesystem events into one, for editors that use swap/backup files during saving". Editors that write a temporary file and rename it can generate a burst of events for what a human sees as one save; coalescing means your command runs once, not several times. Second, watchexec "uses process groups to keep hold of forking programs". A command that spawns children can otherwise leave orphans behind when the parent is killed. The supervisor crate and the process-wrap dependency listed in the README exist for this reason.

Filtering is the other half of the design. The README states that watchexec loads .gitignore and .ignore files. That is what keeps a build from retriggering itself: if your build output directory is already ignored by git, watchexec will not treat writes into it as changes. This is a dependency worth noticing, because it means the tool's behaviour is partly determined by files in your repository rather than by flags on the command line. The README also notes that watchexec provides the paths that changed in environment variables or on STDIN, so a command can know which files moved rather than being told only that something did.

Installing watchexec and running a first real command

The README points to four installation routes: your package manager (it names Arch, Debian, Homebrew, Nix, Scoop and Chocolatey), a pre-built binary from the GitHub releases page, Binstall, or building from source with Cargo. The Cargo route is the one that works identically on every platform the README claims support, which it lists as OS X, Linux and Windows.

bash
cargo install --locked watchexec-cli

The package name is watchexec-cli, not watchexec, because the repository publishes a CLI crate and a library crate separately. The --locked flag makes Cargo use the versions recorded in the lockfile rather than resolving fresh ones. If you prefer not to compile, the README gives the Binstall equivalent.

bash
cargo binstall watchexec-cli

Once the binary is on your PATH, the README's first example watches JavaScript, CSS and HTML files in the current directory and all subdirectories, and runs a build when a change is detected.

bash
watchexec -e js,css,html npm run build

The -e flag takes a comma-separated list of extensions. You should see watchexec start, then run npm run build once, then run it again each time you save a matching file. Files that do not match the extension list are ignored even if they change, which is the simplest way to keep a watcher from firing on unrelated edits.

The second README example uses -r, which restarts the command instead of waiting for it to finish. The README's wording is to "call/restart python server.py" when a Python file changes.

bash
watchexec -r -e py -- python server.py

The double dash separates watchexec's own flags from the command being run, which matters when the command itself has flags that watchexec would otherwise try to parse. The README also points to watchexec -h, watchexec --help and watchexec --manual for the full option list, and to doc/watchexec.1.md for the manual page.

Where watchexec is the wrong tool

watchexec is a development-time convenience, and the README never presents it as anything else. The example use cases are all local loops: run tests, run linters, rebuild artifacts. If you need a process supervisor for production, one that restarts a crashed service, logs to a journal and starts at boot, watchexec's restart flag is not a substitute. It restarts on file modification, not on process exit, and the README documents no health checking, backoff or alerting.

There is a second class of misuse: watching a path that the command itself writes to. The README's answer to this is ignore files, not a flag. If your build writes into a directory that is not covered by .gitignore or .ignore, the write can register as a change and trigger another run. The README does not describe a built-in debounce window you can tune from the command line, so the practical fix is to make the ignore files correct rather than to reach for a timeout option. That is a real constraint on how you adopt the tool: it works best in a repository that already has a disciplined .gitignore.

The README is also silent on several operational questions. It does not document behaviour when the watched path is deleted or becomes unavailable, it does not document resource use on very large directory trees, and it does not describe a maximum watch depth. If your project has a vendored dependency directory with hundreds of thousands of files, the README gives you no guidance on whether to watch it. Treat that as unknown rather than as a supported configuration.

watchexec compared with entr and with language-specific watchers

The most common comparison is with entr, and the difference is in how the file list is produced. entr is designed to read a list of files from STDIN and rerun a command when any of them change, which is why the README of watchexec advertises "simple invocation and use, does not require a cryptic command line involving xargs". With entr you typically pipe a find or git ls-files output into it; with watchexec you name a path and, optionally, an extension filter, and the tool walks the tree itself. That makes watchexec's invocation shorter for the common case, at the cost of giving you less explicit control over exactly which files are in the set.

The other alternative is a watcher built into your language's tooling. A framework dev server that reloads on change is doing the same job as watchexec -r, but it only knows about that framework's files and it only works while that framework's toolchain is installed. watchexec's advantage is neutrality: the same binary can watch a Python server, a Rust crate and a directory of HTML. Its disadvantage is the flip side of the same fact. It does not understand your project. It cannot tell that changing a header should rebuild only the translation units that include it, or that a schema change should regenerate a client before restarting the server. For that kind of dependency awareness you need a build system, and the README itself suggests pairing watchexec with just, described there as "a modern alternative to make". The pairing is the point: watchexec decides when to run, just decides what to run.

Maintenance, releases and what the Apache-2.0 licence means for you

The repository is not archived, and the last push was on 2026-08-24. The most recent releases listed are v2.7.0 on 2026-08-24, v2.6.1 on 2026-08-22 and v2.6.0 on 2026-08-22. Two releases in three days suggests the project is being maintained, but the README does not document a support policy, a release cadence or a compatibility guarantee between minor versions. If you pin watchexec in CI, pin a specific version rather than tracking latest.

The upgrade cost is low for the CLI in normal use, because the flags shown in the README (-e, -r, the double dash) are long-standing core options. The cost is higher if you depend on the library crates. The workspace splits functionality across crates/lib, crates/events, crates/signals, crates/supervisor, crates/ignore-files and crates/project-origins, and a change in any of them can require a coordinated bump in your own Cargo.toml. Building from source also pulls the workspace's release profile settings, which include lto = true, codegen-units = 1 and strip = "symbols". Those settings are tuned for a small, fast binary and they make release builds slow. For a tool you install once that is a good trade; for a crate you compile on every CI run it is worth knowing before you blame your own build.

The licence is Apache-2.0, which is a permissive licence that allows commercial use and modification. This is not legal advice, and the practical obligations (notice retention, patent grant terms, attribution) are worth reading in the LICENSE file at the repository root before you redistribute a modified binary. The README does not discuss licensing of the CLI versus the library crates separately, so if you vendor a crate, check that crate's own manifest.

Editorial conclusion

Adopt watchexec if you want a language-agnostic file watcher installed once and reused across projects: install it with cargo install --locked watchexec-cli or your package manager, then start with watchexec -e js,css,html npm run build. Skip it if you need a persistent service that survives reboots, or if you want a build system that understands dependency graphs; watchexec only knows that something under the watched path changed. Before relying on it in a team, verify three things yourself: how your package manager's build is versioned, what happens to a long-running process under -r when the watch path disappears, and whether your project's .gitignore rules already exclude the build output directories that would otherwise retrigger the command.

Frequently asked questions

How can I monitor file changes in Linux?

Install watchexec and point it at a path; it monitors the current directory and all subdirectories for changes and runs a command when it detects modifications. The README's first example is watchexec -e js,css,html npm run build, which watches those extensions and runs the build. It also loads .gitignore and .ignore files, so ignored paths do not trigger the command.

How can I watch a process in Linux?

watchexec watches a path rather than a process, and restarts the command it runs when a file changes. The README's example is watchexec -r -e py -- python server.py, which calls or restarts the Python server when any Python file changes. It uses process groups to keep hold of forking programs, so children of the command are managed rather than orphaned.

How do I install watchexec on Ubuntu?

The README lists Debian among the package managers it supports and points to doc/packages.md for the per-distribution details, so the distro package is the first route to check. If your Ubuntu release does not carry it, the README also offers a pre-built binary from the GitHub releases page and cargo install --locked watchexec-cli from source.

Does watchexec work on Windows?

Yes. The README states that watchexec runs on OS X, Linux and Windows, and it lists Scoop and Chocolatey among the package managers that carry it. The same CLI flags apply across platforms.

Can I use watchexec as a library instead of the command line tool?

Yes. The repository ships a watchexec library crate plus supporting crates for events, signals and process supervision, and the README describes the library as a way to create more specialised watchexec-powered tools. cargo lambda, devenv.sh, dotter and ghciwatch are listed in the README as downstream users.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community notes

Community notes