Introduction
entr takes a list of filenames on stdin and re-runs a command whenever any of them changes. It's a 1000-line C program with one job, and it composes beautifully with find, ls, fd, and ripgrep. If you've ever written a bespoke fswatch | xargs loop, entr is probably a cleaner replacement.
What entr Does
- Uses kqueue (BSD/macOS) or inotify (Linux) to watch a file set.
- Re-executes a command when any watched file changes.
-rkills a long-running child before restart (server reload).-cclears the screen between runs for clean test output.-sinvokes via shell to support pipelines and redirection.
Architecture Overview
entr reads the file list from stdin once, opens OS-level file descriptors with kqueue/inotify, and blocks on events. On any CHANGE/DELETE, it either execs the command (default) or signals the child with SIGTERM/SIGKILL (-r mode) and re-execs. No daemon, no config file.
Self-Hosting & Configuration
- Install via brew, apt, dnf, pkg.
ENTR_INOTIFY_WORKAROUND=1handles editors that write via replace (VSCode/Vim).- No config files; everything is flags.
- Plays nicely in Docker if you mount the source tree.
Key Features
- Zero dependencies, tiny binary.
- Works with any command — tests, builds, servers, rsync.
-rgives you a poor-person's nodemon/air for any language.- Composable:
fd . src | entr -c go test ./.... - BSD-friendly; runs on OpenBSD, FreeBSD, macOS, Linux.
Comparison with Similar Tools
- nodemon — Node-specific; heavier.
- air — Go-specific reload.
- watchexec — Rust; auto-discovers files, more features.
- modd — YAML config; richer dev-server orchestration.
- fswatch — emits events; pairs with xargs — entr replaces the pipeline.
FAQ
Q: Why does my editor not trigger a reload?
A: Atomic writes — set ENTR_INOTIFY_WORKAROUND=1.
Q: Max file count? A: OS-limited (inotify max_user_watches, kqueue limits).
Q: Works in Docker? A: Yes if inotify is available and the mount propagates events.
Q: Can I pass multiple commands?
A: Use -s "cmd1 && cmd2".