DEV Community

Cover image for Exploring native file watching in Node.js v22
Megan Lee for LogRocket

Posted on • Edited on • Originally published at blog.logrocket.com

Exploring native file watching in Node.js v22

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 or package.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 the nodemon.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
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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: Terminal Open Showing Completed Native File Watching Process In Node Js With Watch Mode Enabled

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
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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 using node --run <script-in-package-json>
  • The addition of glob and globSync methods to the fs 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
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 nearest package.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!";
}
Enter fullscreen mode Exit fullscreen mode

Require the ES module synchronously in your index.js:

// index.js
const esmModule = require("./module.mjs");

console.log(esmModule.greet());
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

Run the scripts using the node --run command:

node --run test
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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 Signup

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)