Taming Nodemon Restarts: A Practical Guide to watch, ignore, delay, and execMap
Nodemon's defaults cause restart loops and thrashing in real projects. Here's how watch, ignore, delay, and execMap in nodemon.json fix that — plus how to verify the config actually behaves.
07 Apr 2026, 09:19 UTC

Your dev server restarts. Then it restarts again. Then three more times, because your app just wrote a log line into the same folder nodemon is watching. If you've used nodemon for more than a day, you've hit this: the tool that exists to save you time starts burning it in restart loops and thrashing reloads.
The fix isn't a different tool. Nodemon's configuration system — specifically the watch, ignore, delay, and execMap options — exists precisely for this problem, and most developers never move past the defaults. This post walks through a config that actually matches how real projects behave.
Where configuration lives (and who wins)
Nodemon accepts settings three ways, in increasing order of precedence:
- A
nodemonConfigkey insidepackage.json - A standalone
nodemon.jsonfile in the project root - CLI flags, which override everything
The practical takeaway: commit a nodemon.json so the whole team shares sane defaults, and let individuals override with flags when debugging. A standalone file is easier to comment-adjacent (via well-named keys) and keeps package.json from bloating.
The restart-loop problem: watch and ignore
By default, nodemon watches the working directory for changes to .js, .mjs, .coffee, .litcoffee, and .json files. That's fine until your application writes files at runtime — uploads, coverage reports, SQLite databases, log files. Every write triggers a restart, which triggers more writes, which triggers more restarts.
The watch and ignore keys accept glob patterns. The reliable pattern is to watch narrowly and ignore aggressively:
{
"watch": ["src", "config"],
"ignore": ["src/**/*.test.js", "logs/*", "uploads/*", "coverage/*"],
"ext": "js,json",
"delay": "500"
}Two things to note here. First, listing watch directories explicitly means nodemon doesn't scan node_modules or build output at all — which also matters on Linux, where watching huge trees can exhaust inotify watcher limits and cause nodemon to silently stop detecting changes. Second, the ignore patterns cover everything your app writes at runtime.
One caveat: nodemon's glob semantics differ subtly from shell globbing. If a pattern isn't behaving, test it in isolation before assuming the rest of the config is broken. A quick check is to run nodemon with --verbose, which prints which files it's watching and what triggered each restart.
Debouncing burst changes with delay
Even with correct watch rules, some operations change many files at once: switching git branches, running a code generator, a transpiler emitting a dozen output files. Without intervention, nodemon restarts once per file event.
The delay option (milliseconds as a string or number) debounces restarts: nodemon waits until changes stop arriving for that window, then restarts once. The "500" in the config above means a branch checkout collapses into a single restart instead of thirty. Tune it based on how slow your toolchain is — a heavy build step might justify 1000–2500ms. The trade-off is obvious: higher delay means a longer wait after a legitimately single edit. 300–500ms is a good starting point for most setups.
Running non-JavaScript entry points with execMap
Nodemon isn't node-specific. The execMap key maps file extensions to executables, so nodemon becomes a generic "restart on change" runner:
{
"execMap": {
"ts": "ts-node",
"py": "python"
}
}With this, nodemon server.ts runs through ts-node instead of failing. This is well-established behavior, but verify the mapped binary is on your PATH (or use an absolute path) — a missing executable fails in ways that look like a nodemon bug.
Verifying the config actually works
Don't trust the file; test the behavior. From your project root:
- Run
npx nodemon --versionfirst. Watched-extension defaults and signal handling have changed across major versions, so confirm the docs you read match what you installed. - Start nodemon with
--verboseand touch a file in an ignored path — you should see no restart. Touch one in a watched path — you should see exactly one. - Type
rsand press Enter in the nodemon terminal to force a manual restart — useful when you've changed something nodemon can't see, like an environment variable. - Add a
process.on('SIGTERM', ...)handler in your app and confirm it fires on restart. Nodemon sends SIGTERM to the child process; if your server doesn't handle it, in-flight requests and database connections die ungracefully on every restart.
The limitation worth remembering
Nodemon is a development convenience, not a process supervisor. It has no clustering, no log management, and no serious crash-recovery semantics. If you're tempted to use it in production because "it restarts the app when it crashes," stop — that's what systemd, PM2, or your container orchestrator is for. Keep nodemon in devDependencies, and keep it out of your deployment path.
Start with the four-key config above, run nodemon with --verbose for one session to confirm the watch set matches your intent, and commit the result. Fifteen minutes of setup eliminates an entire category of "why did it restart again?" debugging.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.