cheat sheet
nodemon
Package-level reference for nodemon on npm — watch globs, exec patterns, config files, and how it compares to node --watch and tsx watch.
nodemon
What it is
nodemon is a long-running file-watcher and process supervisor for Node.js. Point it at a script (or any command), give it a watch pattern, and it restarts the process whenever a matching file changes. It's the daily-driver dev tool that turns "edit → save → manually restart → test" into "edit → save → test".
nodemon predates Node's built-in --watch flag (Node 18.11+) by roughly a decade. It still beats the native flag for richer features: config files, debounce / delay, watch-extension lists, custom exec commands (run tsx, ts-node, or even python under it), shell commands on event hooks, and per-event signals. For a simple dev server, node --watch is enough; for anything else, nodemon remains the standard.
Install
# Project-local (recommended — pin to lockfile)
npm install -D nodemon
pnpm add -D nodemon
yarn add -D nodemon
bun add -d nodemon
Output: nodemon binary in node_modules/.bin/ — invoke via npx nodemon or in an npm script.
# Global (acceptable — nodemon is stable and stateless)
npm install -g nodemon
Output: nodemon on user PATH; per-project pinning still preferred for CI parity.
# One-off
npx nodemon src/server.js
Output: downloads nodemon to the npm cache and runs.
Versioning & Node support
- Current line is
3.x. The3.0release (mid-2023) dropped support for Node 10 and refactored the watch backend for Node 16+ APIs. - Requires Node 10 or newer; in practice everything modern works fine.
- Pure JS, no native bindings — installs without a build step on any platform.
- SemVer respected; minor releases mostly tweak watch defaults and CLI parsing.
- Maintenance is steady but slow — no big roadmap, mostly bug fixes.
Package metadata
- Maintainer: Remy Sharp (
remy) + small contributor pool - Project home: github.com/remy/nodemon
- Docs: nodemon.io
- npm: npmjs.com/package/nodemon
- License: MIT
- First released: 2010
- Downloads: ~50M weekly — among the most-installed dev tools on npm
Peer dependencies & extras
nodemon ships with everything it needs — chokidar for cross-platform file-watching, plus a small CLI helper layer. No peers required.
| Companion | Role |
|---|---|
tsx / ts-node | nodemon doesn't transpile TypeScript itself — pair with --exec tsx src/server.ts to run TS sources. |
dotenv-cli | nodemon --exec "dotenv -- node src/server.js" to load env on each restart. |
@types/nodemon | (none — nodemon doesn't export a programmatic API people import) |
Alternatives
| Tool | Trade-off |
|---|---|
| node --watch (built-in, Node 18.11+) | Native, zero deps. Less configurable — no debounce, no exec hook, no event scripts. Good enough for simple servers. |
| tsx watch | TS-aware watch driven by the import graph. Faster restarts; only watches what's actually imported. No exec hook. |
| chokidar-cli | Lower-level — runs an arbitrary command on file change with no Node-specific affordances. Useful for non-Node watchers. |
| pm2 | Process supervisor; usually overkill for dev. Better suited to production restart-on-crash, not file-change watching. |
| watchexec (non-Node) | Cross-language Rust file-watcher CLI. Great if you need to watch a polyglot repo. |
| vite dev / next dev | Framework-specific dev servers with built-in HMR. Use them where they apply; nodemon for plain Node servers. |
Real-world recipes
Simple watch on a Node server
nodemon src/server.js
Output:
[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node src/server.js`
Server listening on :3000
Type rs + Enter in the terminal to force a manual restart. Default watches the cwd recursively for .js, .mjs, .cjs, .json.
Debounce noisy editors and delay restart
Some editors emit multiple save events per save (atomic write, swap files). --delay debounces and prevents thrashing:
nodemon --delay 500ms src/server.js
nodemon --delay 2 src/server.js # 2 seconds
Output:
[nodemon] file changed: src/api/users.js
[nodemon] file changed: src/api/users.js ← debounced; only one restart
[nodemon] restarting due to changes...
A --delay 500ms value is usually right; tune up if your editor saves in waves.
Run TypeScript via tsx under nodemon
When you want nodemon's globbing rules (or hooks) AND TypeScript:
nodemon --watch src --ext ts,tsx,json --exec "tsx src/server.ts"
Output:
[nodemon] watching extensions: ts,tsx,json
[nodemon] starting `tsx src/server.ts`
Server listening on :3000
[nodemon] restarting due to changes...
[nodemon] starting `tsx src/server.ts`
Use this pattern when tsx watch's import-graph rules miss files you care about (e.g. .json config, fixtures), or when you want to chain dotenv -- tsx ... and add event hooks.
Watch a non-Node command (or anything)
nodemon doesn't require Node. Use it as a generic file-watcher with --exec:
# Re-run a Python script when any .py file changes
nodemon --ext py --exec "python ./main.py"
# Re-build a Go binary and run it
nodemon --ext go --exec "go run ./cmd/server"
# Restart a docker compose stack
nodemon --watch ./docker --ext yml --exec "docker compose up -d --build"
Output:
[nodemon] watching extensions: py
[nodemon] starting `python ./main.py`
[nodemon] restarting due to changes...
Project-level nodemon.json config
{
"watch": ["src", "config"],
"ext": "ts,tsx,json,yaml",
"ignore": ["src/**/*.test.ts", "src/__fixtures__/*"],
"delay": "500ms",
"exec": "tsx src/server.ts",
"events": {
"restart": "echo 'Restarting at $(date)' >> nodemon.log"
},
"env": {
"NODE_ENV": "development",
"LOG_LEVEL": "debug"
}
}
nodemon # picks up nodemon.json automatically
Output:
[nodemon] config: nodemon.json
[nodemon] watching: src, config
[nodemon] starting `tsx src/server.ts`
nodemon.json lives in the project root. Alternative: add a nodemonConfig block in package.json — same schema, no extra file.
Per-event hook scripts
The events block fires shell commands on lifecycle events (start, crash, restart, exit):
{
"exec": "node src/server.js",
"events": {
"start": "echo '🚀 starting'",
"crash": "say 'Server crashed'",
"restart": "curl -s http://localhost:3000/health > /dev/null && echo 'health-pinged'"
}
}
Use crash to alert (desktop notification, Slack webhook) when a dev server dies; restart for warmup pings or cache prime.
Restart only on specific file events
# Only restart on save (default), not on touch / mtime-only changes
nodemon --legacy-watch src/server.js
Output:
[nodemon] starting `node src/server.js`
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] using legacy watch
--legacy-watch falls back to polling — useful on network filesystems, WSL ↔ Windows bridges, and inside Docker volumes where inotify events don't propagate.
Production deployment
nodemon is dev-only. In production:
- Use a real process supervisor (
systemd,pm2, container orchestrator) for crash restart. - Use deploy-time builds; no runtime transpile.
- Never run
nodemonin a container destined for production — the file-watching overhead is wasted, andnodemon's restart-on-change is a security footgun if any deploy-time file is writeable.
The one valid production use of nodemon-style watching is staging environments where editors mount in a writeable volume for live-edit demos — but even there, pm2 --watch or node --watch is a better fit.
Performance tuning
nodemon's default settings are right for most cases. Knobs:
Narrow the watch scope
The biggest win is reducing the number of files watched. Default watch: "." traverses everything; restrict it:
{
"watch": ["src"],
"ignore": ["**/*.test.ts", "node_modules", "dist", ".git"]
}
A .gitignore is NOT used by default — explicit ignore patterns only.
Polling vs native watch
nodemon --legacy-watch # polling, ~1s interval
nodemon --polling-interval 500 # custom polling
Output:
[nodemon] starting `node src/server.js`
[nodemon] using polling
Polling burns CPU but works everywhere. Native (chokidar + inotify / FSEvents / ReadDirectoryChangesW) is faster and lower-power but flaky on virtual filesystems.
Limit extensions
nodemon --ext js,ts --watch src
Output:
[nodemon] watching path(s): src
[nodemon] watching extensions: js,ts
[nodemon] starting `node src/server.js`
The default extension list (js,mjs,cjs,json) is fine; over-broad lists trigger restarts on irrelevant files (.md, .log).
Single-restart per save burst
--delay 500ms (above) is usually enough. For multi-file refactor saves (e.g. global rename), bump to --delay 2s.
Version migration guide
| From → To | Highlights |
|---|---|
| 1.x → 2.x | Switched to chokidar (cross-platform). --exec semantics standardised. |
| 2.x → 3.x | Node 10 dropped. Internal refactor of the CLI parser; some edge-case -- arg-passing fixed. nodemon.json schema unchanged. |
| 3.x ongoing | Minor releases tweak chokidar version and CLI parsing; no breaking changes planned. |
Most projects can stay on whatever nodemon they have unless they're on a 1.x line — the upgrade story is trivial.
Security considerations
- Arbitrary command execution.
nodemon --exec "$(cat /tmp/cmd)"runs whatever's in the command. Don't string-build--execfrom user input; treatnodemon.jsonas code. eventshook scripts. Same as above —events.restart: "rm -rf …"will happily destroy. Revieweventsblocks like any shell script.- Local LAN exposure. nodemon itself doesn't bind a port, but it relaunches your server. If that server binds
0.0.0.0, anyone on the LAN can hit your dev environment between restarts. Pair withhost: "127.0.0.1". - Inotify quota exhaustion. Watching huge directories (entire monorepos,
node_modules) on Linux exhausts the per-user inotify watch limit. Symptom: nodemon silently misses events on later files. Raise/proc/sys/fs/inotify/max_user_watchesor narrow the watch scope. - Source-map exposure. If your
--execchain includes a TS transpiler, the same source-map concerns apply (paths leak into stack traces). Disable inline maps in CI builds.
Testing & CI integration
nodemon is rarely used in CI — there's nothing to "watch" in a one-shot CI run. The common CI use is under the dev-server probe in integration tests:
# Spin up server in background under nodemon, run e2e, then kill
nodemon src/server.js &
SERVER_PID=$!
sleep 2
npx playwright test
kill $SERVER_PID
Output:
[nodemon] starting `node src/server.js`
server listening on http://localhost:3000
Running 8 tests using 4 workers
8 passed (12.4s)
Better pattern: use concurrently or npm-run-all for "run server + tests" in parallel.
Ecosystem integrations
- TypeScript — pair
nodemon --exec tsx src/server.ts. - dotenv —
nodemon --exec "dotenv -- node src/server.js". - NestJS —
nest start --watchuses webpack under the hood, not nodemon. For non-nest projects, nodemon is still standard. - Express, Fastify, Koa — all happy under nodemon; restart on save is the default workflow.
- GraphQL codegen —
nodemon --watch schema.graphql --exec "graphql-codegen && tsx src/server.ts"regenerates types on schema change. - Storybook / Vite / Webpack dev servers — do NOT need nodemon; they have HMR built in.
Troubleshooting common errors
[nodemon] app crashed - waiting for file changes
The wrapped process exited with non-zero. nodemon prints this and waits — fix the bug in your code, save, and nodemon resumes. The error from your code is still visible in stdout above the crash message.
Watcher doesn't pick up changes (WSL / Docker / NFS)
Native filesystem events don't propagate. Switch to polling:
nodemon --legacy-watch src/server.js
Output:
[nodemon] starting `node src/server.js`
[nodemon] using legacy watch
EMFILE: too many open files
The watcher hit the OS file-descriptor limit. Either raise ulimit -n or narrow the watch path.
ENOSPC: System limit for number of file watchers reached
Linux inotify limit. Raise it:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Output:
fs.inotify.max_user_watches = 524288
Restarts are too aggressive
Add --delay 1s and tighten the watch path. Editors that "save as swap then rename" can fire multiple events per save.
nodemon doesn't pass --inspect through
nodemon --inspect src/server.js puts --inspect BEFORE the script name — that flag goes to nodemon, not Node. Use the --exec form:
nodemon --exec "node --inspect src/server.js"
Output:
[nodemon] starting `node --inspect src/server.js`
Debugger listening on ws://127.0.0.1:9229/...
For help, see: https://nodejs.org/en/docs/inspector
When NOT to use this
- Production processes. Use
systemd,pm2, or a container orchestrator's restart policy. - Frontend dev servers. Vite / Webpack / Next ship HMR — file-watch is built in and smarter than nodemon's restart-everything.
- Simple Node servers on Node 18.11+.
node --watch src/server.jsis enough if you don't need exec hooks or fancy globbing. - TS-only dev with imports tracked statically.
tsx watchfollows the import graph — faster and quieter than nodemon globs. - Polyglot pipelines.
watchexec(Rust) handles arbitrary commands with better defaults across languages.
See also
- JavaScript: nodemon — CLI flags, daily-use commands
- JavaScript: node-runtime — built-in
--watchflag - Packages: npm-tsx — tsx watch as a slim alternative
- Concept: filesystem — watchers, inotify, events