entr: run a command when files change, without polling
Run arbitrary commands when files change
At a glance
- What is it?
- entr is a small C utility that watches a list of files on stdin and reruns a command when one of them changes. It is built for tight command line feedback loops, and it depends on kqueue or inotify rather than polling.
- Who is it for?
- entr fits anyone who already has a file list and a shell command and wants the command to rerun on change: test loops, static site rebuilds, language servers started from a terminal. It is the wrong tool when the file set is unpredictable or huge, because the watch list comes from stdin, and it is the wrong tool on Windows outside WSL.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 29 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- eradman/entr5,730 ★ · +42
| Repository | 2026-09-24 | 2026-11-14 |
|---|---|---|
| eradman/entr | 5.7k | 5.7k |
42 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The problem entr solves: rerunning a command when a file changes
Most edit-run-check loops start with a person pressing the up arrow and Enter. That works until the loop is long enough that you stop doing it, or until a build takes thirty seconds and you want it started the moment you save. entr removes the keypress. You give it a list of files on standard input, it watches them, and when one changes it runs the command you passed as arguments. The README frames the goal plainly: "entr was written to facilitate rapid feedback on the command line." That is the whole scope. It is not a build system, it has no dependency graph, and it does not decide what to run. It is the trigger, and you supply the rest.
The intended user is someone working in a terminal who can already produce the file list with a shell command. The man page examples in the README cover rebuilding a project, restarting a Node server, rerunning a SQL script, and reloading a web server. All four are one-liners because the file list is one pipeline away. If you cannot express your watched files as a list of paths, entr is awkward to use, and that constraint is worth understanding before adopting it.
How entr watches files: kqueue, inotify, and a list on stdin
entr does not poll. The README states it uses kqueue(2) or inotify(7) to avoid polling. On BSD and macOS the kernel facility is kqueue; on Linux it is inotify. The practical consequence is that idle CPU use is near zero and reaction time is bounded by the kernel notification path rather than by a sleep interval.
The data flow is unusual and worth stating explicitly. entr reads newline-separated paths from stdin, registers each one with the kernel watch mechanism, and then blocks. When the kernel reports an event on a watched descriptor, entr runs the command. Because the file list arrives on stdin, the shell pipeline is the configuration format. There is no config file and no ignore syntax. The README's rebuild example shows the shape:
find src/ | entr -s 'make | head -n 20'Here find produces the list, entr watches it, and the -s flag tells entr to hand the string to a shell rather than exec it directly. The pipe to head limits output to the first 20 lines, which keeps a noisy build from scrolling your terminal away.
Two environment variables modify this behaviour. ENTR_FOLLOW_SYMLINK makes entr follow symlinks on macOS and Linux; the README says symlinks are not followed unless it is set. ENTR_INOTIFY_WORKAROUND exists for environments where inotify is incomplete. Both are opt-in, and both change what gets watched, so they belong in your shell environment rather than buried in a wrapper script you will forget about.
Installing entr from source and running a first watch loop
The repository has no published GitHub releases, so the documented path is a source build. The README gives the standard three steps for BSD, macOS and Linux. Run them from the repository root:
./configure
make test
make installconfigure writes the build configuration, make test builds and runs the test suite, and make install places the binary. The README notes that ./configure -h lists available build options, so check that output if the defaults do not match your platform. The repository ships per-platform makefiles (Makefile.bsd, Makefile.freebsd, Makefile.linux, Makefile.macos), which is a hint that the configure step is doing real platform detection rather than generating a generic makefile.
Once installed, the smallest useful loop is to watch a directory listing and rerun a command. This example comes from the README's man page section and reloads a Node server when any JavaScript file in the current directory changes:
ls *.js | entr -r node app.jsThe -r flag restarts the command rather than running it alongside the previous invocation, which is what you want for a long-lived server. Without it you would accumulate processes. What you should see after running this is the server starting once immediately, then restarting each time you save a .js file, with no polling delay.
A second pattern covers the case where the command needs the name of the changed file. The README's SQL example writes the changed path into the command as /_:
echo my.sql | entr -cp psql -f /_The -c flag clears the screen before each run, matching the README's description of this example: clear the screen and run a query after the SQL script is updated. That substitution is the mechanism that makes entr usable for single-file tools such as linters and interpreters. Note that the README uses echo here to feed a single path; a find or ls pipeline works the same way.
Where entr breaks: incomplete inotify, symlinks, and the -d restart loop
The README is candid about one failure mode. Incomplete inotify support on Windows Subsystem for Linux and Docker for Mac "may cause entr to respond incorrectly." The workaround is to set ENTR_INOTIFY_WORKAROUND. This is not a bug you can patch around in your own script; it is a property of the filesystem notification layer those environments expose. If you develop inside Docker for Mac and expect host-side file edits to trigger a rebuild, test this before you build a workflow on it.
Symlinks are the second sharp edge. On macOS and Linux they are not followed unless ENTR_FOLLOW_SYMLINK is set, so a watched path that is a link to the real file may not fire when the target changes. Projects with symlinked source trees, or with node_modules-style link farms, need to decide this deliberately.
The third limitation is structural rather than environmental. entr watches exactly the files you list. If a new file appears that was not in the original list, entr is not watching it. The README addresses this with a shell loop that re-enumerates and restarts entr each time it exits:
while sleep 0.1; do ls src/*.rb | entr -d make; doneThe -d flag makes entr exit when a file is added to a watched directory, so the outer loop rebuilds the list. This works, but note what it costs: the outer loop sleeps 0.1 seconds, which reintroduces polling at the shell level, and every restart of entr tears down and recreates the kernel watches. For a large tree this is measurably worse than watching a fixed list. If your project adds files constantly, a tool that watches directories natively will be a better fit than this pattern.
entr compared with watchman and watchexec
The closest alternatives take a different approach to the same problem. Facebook's watchman maintains a persistent server that indexes a directory tree, keeps watches across invocations, and answers queries about what changed since a given clock. entr has no daemon: it is a foreground process that dies when you close the terminal, and its watch list is whatever the pipeline produced. The difference shows up in startup cost and in scope. watchman amortises the cost of scanning a large tree across many invocations; entr pays it once per pipeline, which is trivial for a src/ directory and painful for a monorepo with hundreds of thousands of files.
watchexec, written in Rust, sits closer to entr in spirit: a foreground process that runs a command on change. The difference is in the argument surface. watchexec takes glob patterns and ignore rules as flags, so filtering happens inside the tool. entr pushes filtering into the shell, which is why the README's examples all begin with find or ls. If you prefer ignore rules in a config file, that is a point against entr. If you prefer composing with the tools you already know, it is a point for it.
There is also the question of what happens to the child process. entr's -r flag restarts a long-lived command and -z makes entr terminate if the server exits, which the README demonstrates with `ls * | entr -rz ./httpd`. That combination is a compact supervisor for a development server. Tools that only rerun short commands make you write that supervision yourself.
Maintenance, licensing, and what a source build costs you
The repository is not archived, and the last push was on 2026-10-16. That is recent enough that the project is being touched, but the README offers no release cadence and the repository has no published releases, so treat upgrades as something you initiate rather than something announced to you. The README points at an Atom feed for release notifications (https://github.com/eradman/entr/releases.atom) and at the NEWS file for release history. If you run entr on a build server, subscribing to that feed is cheaper than discovering a behaviour change after an upgrade.
Upgrade cost is low in one sense and non-trivial in another. entr is a single C program with no runtime dependencies beyond the platform's notification API, so replacing the binary is the whole upgrade. But it is built from source, which means the upgrade path is the same ./configure && make install sequence, run on each machine or baked into an image. There is no package manager step documented in the README, so the packaging you use is your distribution's, not the project's, and its version may lag the repository.
The licence field reports NOASSERTION, meaning the repository's licence could not be classified automatically. The LICENSE file is present at the top level. Read it before redistributing entr inside a product or a container image, and if the terms matter to your legal team, that file is the source of truth rather than any summary. This is a note about where to look, not advice on what the terms permit.
Editorial conclusion
entr fits anyone who already has a file list and a shell command and wants the command to rerun on change: test loops, static site rebuilds, language servers started from a terminal. It is the wrong tool when the file set is unpredictable or huge, because the watch list comes from stdin, and it is the wrong tool on Windows outside WSL. Before adopting it, verify two things on your own machine: that the default build succeeds with ./configure && make test, and that your workload behaves with ENTR_INOTIFY_WORKAROUND set if you run inside Docker for Mac or WSL, since the README states inotify support there is incomplete. If your change detection needs to survive a process restart or cover a directory tree you cannot enumerate cheaply, entr is the wrong layer.
Frequently asked questions
How does entr work?
entr reads a newline-separated list of file paths from standard input, registers each path with kqueue(2) or inotify(7), and runs the command you passed as arguments when one of those files changes. The README states it uses these kernel facilities to avoid polling.
How do I install entr?
The README documents a source installation for BSD, macOS and Linux: run ./configure, then make test, then make install. To see available build options, run ./configure -h.
Why does entr not respond to file changes in Docker or WSL?
The README states that incomplete inotify support on Windows Subsystem for Linux and Docker for Mac may cause entr to respond incorrectly, and that setting the ENTR_INOTIFY_WORKAROUND environment variable enables entr to operate in those environments.
Does entr follow symlinks?
On macOS and Linux, the README says symlinks are not followed unless the ENTR_FOLLOW_SYMLINK environment variable is set.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/eradman-entr)Star history chart for your README
[](https://hysenlabs.com/projects/eradman-entr)Was this useful?