cheat sheet

nodemon

Daily-driver reference for nodemon — watch flags, exec patterns, config files, lifecycle events.

nodemon — CLI

What it is

nodemon watches files and restarts a wrapped command when something changes. Default-target is Node, but --exec makes it run anything. It's the long-time default dev-loop tool for Node servers. The native node --watch flag (Node 18.11+) covers the simple case, but nodemon's globs, debounce, config file, and event hooks are still worth the dependency.

For the package overview, see packages-npm/npm-nodemon. This page focuses on the CLI.

Install

bash
npm install -D nodemon
# or
npm install -g nodemon

Output: nodemon binary in node_modules/.bin/ or on user $PATH.

Day-to-day commands

CommandWhat it does
nodemon src/server.jsWatch *.js,*.mjs,*.cjs,*.json in cwd; restart server on save
nodemon --watch src src/server.jsWatch only the src/ directory
nodemon --ext ts,tsx --exec "tsx src/server.ts"Run a TS server, restart on .ts/.tsx change
nodemon --delay 500ms src/server.jsDebounce restarts
nodemon --legacy-watch src/server.jsPolling watcher (WSL/Docker compatibility)
nodemon --inspect src/server.jsPass --inspect to Node (debugger port)
nodemon -e py --exec "python main.py"Use as a generic file-watcher for any command
nodemon --ignore "**/*.test.ts" src/server.tsIgnore certain files
nodemon (no args, with nodemon.json)Load config from nodemon.json

rs<Enter> in the terminal forces a manual restart.

Common scenarios

Watch a TS server

bash
nodemon --watch src --ext ts,tsx,json --exec "tsx src/server.ts"

Output:

text
[nodemon] 3.1.0
[nodemon] watching path(s): src
[nodemon] watching extensions: ts,tsx,json
[nodemon] starting `tsx src/server.ts`
Server listening on :3000
[nodemon] file changed: src/api/users.ts
[nodemon] restarting due to changes...

Use nodemon.json to keep CLI short

json
{
  "watch": ["src", "config"],
  "ext": "ts,tsx,json,yaml",
  "ignore": ["src/**/*.test.ts"],
  "delay": "500ms",
  "exec": "tsx src/server.ts",
  "env": {
    "NODE_ENV": "development",
    "LOG_LEVEL": "debug"
  }
}
bash
nodemon

Output:

text
[nodemon] config: nodemon.json
[nodemon] watching extensions: ts,tsx,json,yaml
[nodemon] starting `tsx src/server.ts`

Pass arguments through to the script

bash
nodemon src/server.js -- --port 3001 --verbose

Output:

text
[nodemon] starting `node src/server.js --port 3001 --verbose`
server listening on http://localhost:3001

Everything after -- is forwarded to the wrapped process. Without --, nodemon swallows them as its own flags.

Lifecycle hooks (run shell commands on events)

json
{
  "exec": "node src/server.js",
  "events": {
    "start": "echo '🚀 starting'",
    "restart": "curl -s http://localhost:3000/health",
    "crash": "say 'Server crashed'"
  }
}

Useful for: warmup pings, desktop notifications on crash, Slack webhooks.

Debug mode

bash
nodemon --exec "node --inspect-brk src/server.js"

Output:

text
[nodemon] starting `node --inspect-brk src/server.js`
Debugger listening on ws://127.0.0.1:9229/...

The --inspect-brk flag belongs to Node, not nodemon — pass via --exec. Then attach VS Code or Chrome DevTools.

Polling watcher for WSL / Docker / NFS

bash
nodemon --legacy-watch --polling-interval 500 src/server.js

Output:

text
[nodemon] starting `node src/server.js`
[nodemon] using polling (500ms)

Native file events don't always propagate across virtual filesystems. Polling is slower but reliable.

Generic command-runner

bash
# Re-build Go on .go changes
nodemon -e go --exec "go run ./cmd/server"

# Rebuild docker stack
nodemon --watch ./docker --ext yml --exec "docker compose up -d --build"

Output:

text
[nodemon] watching extensions: go
[nodemon] starting `go run ./cmd/server`

Useful flags

FlagWhat it does
--watch <path>Add a path to watch (default: cwd)
--ignore <pattern>Ignore matching files
--ext <list>Comma-separated extensions to watch
--exec <cmd>Command to run on each restart
--delay <time>Debounce restarts (500ms or 2)
--legacy-watchUse polling instead of native FS events
--polling-interval <ms>Tune polling interval
--no-restart-afterDon't restart after a crash
--signal <SIGNAL>Signal sent on restart (default SIGTERM)
--quietSuppress nodemon's own log lines
--verboseExtra logging
--config <path>Use a non-default config file
--inspectConvenience pass-through to Node (without --exec)
--dumpPrint resolved config and exit

Configuration

nodemon.json (in project root) or nodemonConfig block in package.json:

json
{
  "name": "my-app",
  "scripts": {
    "dev": "nodemon"
  },
  "nodemonConfig": {
    "watch": ["src"],
    "ext": "ts,tsx,json",
    "exec": "tsx src/server.ts",
    "delay": "500ms",
    "env": {
      "NODE_ENV": "development"
    }
  }
}

Schema summary:

KeyTypePurpose
watchstring[]Paths to watch
ignorestring[]Patterns to skip
extstringComma-separated extensions
execstringCommand to run
delaystring/numberDebounce duration
envobjectExtra env vars for the wrapped process
eventsobjectShell commands keyed by event name
signalstringSignal sent on restart
legacyWatchbooleanForce polling

Common pitfalls

  1. --inspect flag goes to nodemon, not Node. Use --exec "node --inspect src/server.js" instead.
  2. WSL/Docker volumes miss changes. Switch to --legacy-watch.
  3. Linux inotify watch limit exhausted. ENOSPC error — raise fs.inotify.max_user_watches or narrow the watch scope.
  4. .gitignore is NOT honoured by default. Use explicit ignore patterns.
  5. Editor atomic-write fires multiple events. Bump --delay to debounce.
  6. Cannot find module after a restart. Probably restarted before npm install finished — wait then rs.
  7. Restart on irrelevant file (e.g. .log). Tighten ext and ignore.

See also