Built-in Watch Mode (--watch)
Since Node.js 18.11 (stable in 19+), you can restart a Node process automatically when source files change by passing the --watch flag — no nodemon installation required. Node watches the files it has require()d or import()ed and restarts the process when any of them change. There's also --watch-path for watching specific directories and fs.watch() for programmatic file watching without restarting.
Basic usage
# Restart server.js whenever any of its imported files change: node --watch server.js # Node 22+: also supports TypeScript via --experimental-strip-types: node --watch --experimental-strip-types server.ts # Watch a specific directory (not just imported files): node --watch-path=./src server.js # Combine with --env-file: node --watch --env-file=.env server.js
Restarting 'server.js' Server listening on :3000 (file change detected) Restarting 'server.js' Server listening on :3000
--watch vs nodemon
Feature |
|
|
|---|---|---|
Installation | None — built in |
|
File watching | Files actually required/imported | Glob patterns (configurable) |
Watch config file | Not supported |
|
Extension filtering | Not supported directly |
|
Delay before restart | Not configurable |
|
Exec non-Node commands | No | Yes — |
Node version required | 18.11+ | Any |
With tsx for TypeScript
# tsx has its own --watch mode (preferred for TypeScript): npx tsx --watch src/server.ts # Or use node --watch with tsx as the loader: node --watch --import tsx/esm src/server.ts
// package.json scripts:
{
"scripts": {
"dev": "tsx --watch src/server.ts",
"dev:node": "node --watch --env-file=.env src/server.js"
}
}Programmatic file watching with fs.watch
import fs from 'node:fs'
import path from 'node:path'
// Watch a single file:
const watcher = fs.watch('./config.json', (eventType, filename) => {
console.log(`${filename} changed (${eventType})`)
reloadConfig()
})
// Watch a directory recursively (Node 19.9+ on all platforms):
const dirWatcher = fs.watch('./src', { recursive: true }, (eventType, filename) => {
if (filename?.endsWith('.ts')) {
console.log(`TypeScript file changed: ${filename}`)
}
})
// Always stop watching on cleanup:
process.on('SIGTERM', () => {
watcher.close()
dirWatcher.close()
})