Written by Oghenetega Denedo✏️
Keeping tabs on file changes during development is an essential part of the workflow for most Node.js developers. It's all about detecting changes in files to set off actions like server reloads, code recompiles, or automated testing.
With native file watching now in place in Node.js, you no longer have to worry about manually updating your development environment whenever you make changes in the codebase.
In this article, we will look at the file watching feature built into Node.js and how it measures up against Nodemon. We will also walk you through migrating from Nodemon to native file watching and highlight other updates with this Node.js release.
The role of Nodemon before native file watching
Nodemon is a widely used utility in the Node.js ecosystem that's helped enhance developer productivity to quite an extent. It ensured that developers no longer had to stop and start their server again and again after every change made during development.
How Nodemon became an integral tool for Node.js developers
Nodemon’s simplicity and usability made it a vital tool for any Node.js developer looking to have a stress-free development process. Before Nodemon was introduced, manual restarts were time-consuming and stressful.
Nodemon's ability to automate this task was a game-changer, providing:
- Greater productivity: Developers could be more productive because they didn’t need to spend time rebooting the server after each change to the code
- Consistency: Automated restarts made sure changes were consistently applied to reduce the likelihood of errors or unexpected behaviors because of an outdated version of the code.
- Smooth community adoption: With a very active community at its back, Nodemon has been integrated into many setups for Node.js development as a result of extensive documentation, tutorials, and community contributions
Nodemon really improved the development workflow by automating restarts, which was very important before the introduction of native file watching. But with a stable native file watching feature in the latest Node release, we may no longer need to rely on third-party solutions like Nodemon or Turbowatch.
Native file watching vs. Nodemon
The native file watching implementation aims to bring a new dynamic into the Node development workflow for so many developers out there. Does that mean Nodemon is no longer necessary? Let’s compare native file watching with Nodemon based on features and usability in general.
Feature comparison
Native file watching in Node.js offers important features, like:
- Built-in support: Directly integrated into Node.js, eliminating the need for external tools
- Simplicity: Minimal setup is required, utilizing simple flags such as
--watch
and--watch path
- Configuration: Allows specifying watch paths and includes options like
--watch-preserve-output
to control console behavior during restarts - Performance: Optimized for performance within the Node.js runtime, reducing overhead compared to external tools
- Limitations: Currently offers fewer advanced features than Nodemon
However, Nodemon still offers many benefits, such as:
- Ease of use: Automatically restarts your application when file changes in the directory are detected
- Configuration: Configuration options can be defined through
nodemon.json
orpackage.json
. Developers can specify files or directories to watch, files to ignore, and delay before restart - Cross-platform support: Consistent performance across different operating systems
- Custom executables: Supports running non-Node scripts by specifying executables through the
execMap
property in thenodemon.json
config file - Manual restart: Provides a manual restart option using the
rs
command during development - Advanced features: Supports custom events and signals for graceful shutdown
Here’s a summary of the key differences between Nodemon and native file watching:
Feature | Native file watching | Nodemon |
---|---|---|
Installation | Built-in with Node.js (requires version 18.11.0 or higher) | Requires npm or yarn installation (npm install -g nodemon) |
Usage | node --watch app.js | nodemon app.js |
Configuration | Basic path watching options | Extensive configuration via nodemon.json or package.json |
Extensions supported | Limited to JavaScript by default | Extensive, can monitor various file types |
Manual restart | Not available | Supports manual restart by entering the rs command |
Custom executables | Not available | Supports custom executables via execMap |
Event triggering | Not available | Supports event hooks for restart, start, quit, etc. |
So, while stable native file watching support in Node.js is undoubtedly a huge win, there are still some use cases where you might need the more advanced features offered by Nodemon.
Choosing the right tool
The choice between native file watching and Nodemon largely depends on your use case and development needs:
- Native file watching is ideal for developers seeking a seamless, integrated solution with minimal setup
- Nodemon is better suited for those requiring extensive configuration and advanced features
Consider the strengths and limitations of each tool to make an informed decision and choose the option that best suits your project requirements and workflow preferences.
Transitioning to native file watching
To use native file watching in your development projects, you must have Node.js installed and a version compatible with it. Open your terminal and enter the command below to see what version of Node is installed on your machine:
node -v
If the output from the command you entered in your terminal was at least version 18.11.0, you're good to go! If not, you'll need to update the Node.js runtime installed on your machine to a more recent version from the Node.js website.
Next, go to any empty folder of your choice and create a new file called index.js
with the following code:
console.log("Native File Watching Demo");
Enabling watch mode
To start using native file watching, use the --watch
flag when starting your Node.js application. This approach simplifies the setup, as you no longer need an external tool to keep track of changes:
node --watch index.js
By running the above command, Node.js will watch the index.js
file and all required or imported modules and automatically rerun the process when any watched files change:
Watching specific paths
If you want to watch specific directories, you can do so by using the --watch-path
flag. It allows you to limit file watching to certain paths, which can be useful for large projects with numerous files. You can reduce unnecessary resource usage by focusing only on the directories that matter:
node --watch-path=./src --watch-path=./tests index.js
This ensures that only the src
and tests
directories are monitored.
It's also worth noting that when specifying the paths to watch, the default behavior when using the --watch
flag to watch for imported or required modules is disabled.
Migrating a project from Nodemon to native file watching
Migrating an existing project from Nodemon to native file watching involves updating your setup to leverage Node.js's built-in capabilities. Here's how you can smoothly make the switch.
Start by updating your package.json
start scripts to use the native file-watching flag instead of invoking Nodemon. This change reduces the dependencies in your project and leverages Node.js's built-in capabilities:
{
"scripts": {
"dev": "node --watch index.js"
}
}
Use the --watch-path
flag if your project structure requires watching specific directories. For example, to watch both the src
and tests
, modify the dev
script as follows:
{
"scripts": {
"dev": "node --watch-path=./src --watch-path=./tests index.js"
}
}
By default, the console output is cleared when there are restarts in watch mode. This behavior can be useful to avoid clutter, but it might also remove important debugging information. Use the --watch-preserve-output
flag to preserve the console output for easier debugging:
{
"scripts": {
"dev": "node --watch --watch-preserve-output index.js"
}
}
After these changes, use the appropriate npm or Yarn command to start your application in development mode as usual.
Other notable updates in Node.js v22
Node.js v22 introduced several updates, improving various aspects of the runtime. Among these updates are:
- The native web socket client being enabled by default
- Support for
require()
to load synchronous ES modules under the--experimental-require-module
flag - An experimental feature to execute scripts from
package.json
usingnode --run <script-in-package-json>
- The addition of
glob
andglobSync
methods to thefs
module for file path pattern matching
Let’s take a quick look at each of these updates and why they make this Node release so exciting.
WebSocket client now enabled by default
In Node.js v21, a browser-compatible WebSocket client was introduced as an experimental feature, requiring the --experimental-websocket
flag to enable it:
node --experimental-websocket index.js
With Node.js 22, the WebSocket client is now stable and enabled by default, eliminating the need for the experimental flag.
Here's how to set up a simple WebSocket server connection with the WebSocket
global:
const socket = new WebSocket("ws://localhost:8000");
socket.addEventListener("open", (event) => {
socket.send("Hi!");
});
socket.addEventListener("message", (event) => {
console.log("Message: ", event.data);
});
This update provides a WebSocket client to Node.js without external dependencies, simplifying real-time communication in your applications.
Importing ES modules with require()
Node.js 22 introduces support for requiring synchronous ES modules using the require()
function under the experimental flag --experimental-require-module
to make projects using the older CommonJS module system compatible with ES modules.
To use this feature, enable the experimental flag:
node --experimental-require-module index.js
Some of the requirements for using this feature are:
- The module must be explicitly marked as an ES module with
"type": "module"
field in the nearestpackage.json
or have a.mjs
extension - The module must be fully synchronous (i.e., it should not contain any top-level
await
)
Here is how to import an ES module in a CommonJS module. First, create your ES module:
// module.mjs
export function greet() {
return "Hello from ESM!";
}
Require the ES module synchronously in your index.js
:
// index.js
const esmModule = require("./module.mjs");
console.log(esmModule.greet());
Using the require()
function, the specified ESM module is loaded synchronously, and its namespace object is returned. This is similar to the dynamic import()
, but without the asynchronous behavior. When you run the code, you should see the following output in your terminal:
Hello from ESM!
(node:40861) ExperimentalWarning: Support for loading ES module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
The warning message you’ll see in your terminal is because the feature is still experimental.
This enhancement aims to provide a smoother integration between CommonJS and ES modules, which is expected to become stable in future Node.js releases.
Running package.json
scripts
A new experimental feature in this Node.js release lets you execute scripts defined in package.json
using the node --run
command. This offers a faster alternative to running scripts than npm run <script>
.
To use this feature, define scripts in your package.json
:
{
"scripts": {
"test": "node test.js"
}
}
Run the scripts using the node --run
command:
node --run test
The node --run
feature focuses on top performance for common use cases. It doesn’t aim to match the behaviors of npm run
or other package managers. Some intentionally excluded features are:
- Running pre or post scripts in addition to the specified script
- Defining package manager-specific environment variables
With this new feature, the development workflow gets faster by executing scripts directly from the command line using Node.js.
File pattern matching with glob
and globSync
Two new functions, glob
and globSync
, were added to the fs
and fs/promises
modules to make it easier for developers to match file paths based on a specified glob pattern.
Here's how you can use it asynchronously:
// Using glob (asynchronous)
const { glob } = require('node:fs');
// Pattern to match all JavaScript files in the current directory and subdirectories
const pattern = "**/*.js";
glob(pattern, (err, matches) => {
if (err) throw err;
console.log(matches);
});
Here's how you can use it synchronously:
// Using globSync (synchronous)
const { globSync } = require('node:fs');
// Pattern to match all JavaScript files in the current directory and subdirectories
const pattern = "**/*.js";
const matches = globSync(pattern);
console.log(matches);
Since this feature is still experimental, you might get the following warning message when you use it:
(node:31707) ExperimentalWarning: globSync is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
For more information and to explore other relevant updates in Node.js 22, check out the docs and official release notes.
Conclusion
Native file watching being stable in Node.js 22 raises a question: is it a worthy candidate to replace the industry favorite Nodemon?
While Nodemon offers several useful functionalities out of the box, the native file watching feature is directly integrated into the runtime and provides ease of use that will make it an attractive option for many developers.
Now, it's up to developers like you and me to try it and share our experiences to help shape the future of Node.js tooling. Happy coding!
200s only✓ Monitor failed and slow network requests in production
Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third-party services are successful, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.
Top comments (0)