In development environments, especially those that involve lots of iterations, we do not want to restart our server or backend app manually when we make changes to our source code.
This is an issue that Nodemon solves. It acts as a utility library for keeping track of server changes and automatically restarts our app for us.
According to the documentation, Nodemon is a perfect tool for development in Node.js-based applications. Indeed, it was built with the properties of the Node’s CLI command in mind, since it is a wrapper around the node
command.
Basically, it works by detecting changes in the current directory of our source code, and restarts the server to cater to these new changes.
Recall that in order to run a Node.js app, we begin with the node
command and append the file name. In development with Nodemon, all we need to do is run Nodemon filename
, and Nodemon will watch our files for us.
However, to make use of Nodemon, we need to install it globally on our machines or locally on a per-project basis.
When installed on a per-project basis, all we need to do is update the script
tag in the package.json
file of our project. To use Nodemon in development mode, we can add a "dev": "nodemon app.js"
line to the script
tag in the same file.
When installed globally, Nodemon is available on our system path and works out of the box.
In this tutorial, I will explain how Nodemon works by exploring its features and how they are being used.
We will cover the following:
In order to follow along with this tutorial, readers should have a basic understanding of Node.js and Express.
As I earlier mentioned, Nodemon is a utility or a helper tool that watches for file changes and automatically restarts our Node.js applications. It is open source, well maintained, and used by lots of people in the community.
To see a list of available Nodemon commands, we can use the -h
flag or the --help
flag shown below. So we can either run:
nodemon -h //or nodemon --help
There are several reasons why we should use Nodemon in developing Node.js based applications.
Firstly, it is very easy to set up. Secondly, once it is installed, it runs automatically, as it doesn’t require any instance to call, and lastly, it aids faster iterations for development environments.
Now, let’s explore how we can install Nodemon below.
As we earlier mentioned, Nodemon can either be installed globally on our system path, or locally as a development dependency.
To install Nodemon globally on our path, we can go ahead and run the command below with the global -g
flag:
npm install -g nodemon
This means that the package can be used and run from the system path on our development machine.
Otherwise, we can run:
npm install --save-dev nodemon
The above command will install Nodemon locally on our machine or as a development dependency. Note here that we are installing Nodemon as a development dependency with the --save-dev
flag, as we do not want it as a production dependency.
When Nodemon is installed globally, we do not need to do any other setup on our local environment as we can run Nodemon from any path on our system and it will watch our source files for us.
After running the above command, our package.json
file will be modified and the Nodemon library with its version number will be saved under the key "devDependencies"
as shown below:
{ "name": "test-app", "version": "1.0.0", "description": "", "main": "index.js", } "scripts": { "test": "echo \"Error: no test specified\" && exit 1" } { "author": "", "license": "ISC", "private": false, "devDependencies": { "nodemon": "^2.0.7" }, }
As a development dependency, all we need to do is add a dev
script in our package.json
file to be able to use Nodemon in our local setup. Let us now proceed by displaying a simple Node.js application to understand all the features and configuration options for Nodemon.
Let’s start small with the server setup located in the app.js
file. The contents of that file is shown below:
require('dotenv').config() require('./mongoClient') const express = require('express') const config = require('./config') const routes = require('./routes') const app = express() // add routes here routes(app) // catch 404 and forward to error handler app.use((req, res, next) => { const err = new Error('Not Found') console.log(err) err.status = 404 res.send('Route not found') next(err) }) app.listen(process.env.PORT || config.port, () => { console.log(`${config.appName} listening on port ${config.port}!`) }) module.exports = app
Let us also have a look at how to run this server file using Nodemon. The very basic and minimal setup for making use of Nodemon in our project is shown below in the package.json
file located in the root:
{ "name": "nodemon_tutorial", "version": "1.0.0", "description": "A Tutorial for Understanding Nodemon", "main": "app.js", "scripts": { "start": "node app.js", "dev": "nodemon app.js" }, "directories": { "model": "model", "controllers": "controllers" }, "repository": { "type": "git", "url": "" }, "keywords": [ "Node.js", "JavaScript" ], "author": "Alexander Nnakwue", "license": "MIT", "devDependencies": { "nodemon": "^2.0.4" }, "dependencies": { "bcrypt": "^5.0.1", "debug": "^4.1.1", "dotenv": "^8.2.0", "express": "^4.17.1", "express-async-handler": "^1.1.4", "mongoose": "^5.9.25", "mongoose-paginate": "^5.0.3", "path": "^0.12.7", "uuidv4": "^6.2.0" }, "engines": { "node": "13.7.0", "npm": "6.13.6" } }
As we can see from the setup in the scripts tag below:
"scripts": { "start": "node app.js", "dev": "nodemon app.js" },
So when we run npm run dev
, it runs Nodemon and watches our files for us.
The content when we run the file with Nodemon is shown below:
[nodemon] clean exit - waiting for changes before restart [nodemon] restarting due to changes... [nodemon] starting `node app.js` (node:97775) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time Nodemon_tutorial listening on port 5000! mongodb connected Mongoose: users.createIndex({ email: 1 }, { unique: true, background: true }) Mongoose: users.createIndex({ phoneNumber: 1 }, { unique: true, background: true })
Any output from this script is prefixed with
[nodemon]
, otherwise all output from your application, errors included, will be echoed out as expected.
With the --inspect
flag (useful for a Node.js process listening for a debugger) in the package.json
file, the output when we run npm run dev
is shown below:
retina@alexander backend-server % npm run dev > [email protected] dev /Users/retina/Dropbox/My Mac (alexander)/Desktop/nodemon_tutorial/nodemon_tutorial > nodemon --inspect app.js [nodemon] 2.0.7 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node --inspect app.js` Debugger listening on ws://127.0.0.1:9229/8618d563-210c-4070-bed5-b077016abae2 For help, see: https://nodejs.org/en/docs/inspector (node:98970) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time Nodemon_tutorial listening on port 5000!
As of version 1.1.x
, Nodemon will search for a scripts.start
property or a main
property in the package.json
file in the current working directory and start the app for us.
Let’s try this out:
(aba) retina@alexander backend-server % nodemon [nodemon] 2.0.7 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node app.js` (node:99661) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time Nodemon_tutorial listening on port 5000! mongodb connected Mongoose: users.createIndex({ email: 1 }, { unique: true, background: true }) Mongoose: users.createIndex({ phoneNumber: 1 }, { unique: true, background: true })
As we can see from the above, our app still works as it should. Note that here, I have deleted the scripts
property from the package.json
file and rerun the app with just the nodemon
command:
// delete the script tag and run nodemon afresh "scripts": { "start": "node app.js", "dev": "nodemon app.js" }
For this to work, we needed to have nodemon
globally installed in our system path. The output when we run the command npm i nodemon -g
to install Nodemon globally is shown below:
retina@alexander ~ % npm i nodemon -g /usr/local/bin/nodemon -> /usr/local/lib/node_modules/nodemon/bin/nodemon.js > [email protected] postinstall /usr/local/lib/node_modules/nodemon > node bin/postinstall || exit 0 + [email protected] added 120 packages from 57 contributors in 13.404s
Nodemon supports both local and global configurations the same way we can configure the system globally or on a per-project basis.
For a local setup, we can have a nodemon.json
file in the current working directory of our project, and for a global setup, we can have the same file in our system’s home path.
Also, we can set up a nodemonConfig
in the projects package.json
file for those who prefer to keep all their package configurations in a single place.
Note that these configurations come with a caveat when it comes to which ones are executed. If we specify a --config
file or provide a local nodemon.json
file, any package.json
config is ignored.
As you may have noticed, there are three ways of configuring Nodemon for development – local, global, and via the Node CLI. When we type nodemon --help options
, we get to see all the available CLI options for our use.
For more info on available ways to configure Nodemon, we can also type *nodemon --help config*
on our terminal.
Typically the options to control Nodemon are passed in via the CLI and can be listed when we run nodemon --help option
.
Now, let’s examine some of the several configurations that we can add by passing more parameters to a configuration(--config
) file or to our nodemon.json
file. Some of these configurations might be useful while developing our projects. Let’s take a look at some of them below.
Nodemon by default monitors the current working directory, but this can be altered by using the --watch
option to add specific paths.
For instance, we can instruct Nodemon to only watch for changes in our services
directory or in the app.js
file in the nodemon_tutorial
directory by running the command below:
nodemon --watch nodemon_tutorial/app.js --watch services
Always add a
--watch
flag for each directory we intend to watch. This usually is required when multiple directories are passed.
Since Nodemon by default restarts a web server when there are file changes, we can effectively change this default setting by configuring Nodemon to ignore changes made in some specific files, directories, or file patterns via the command line.
See an example below where we ignore the tests
folder:
nodemon --ignore tests/
The above command, when run, will automatically ignore any changes made in the tests
folder. Also, note that by default Nodemon ignores files in the node_modules
and .git
folder. Amazing right? Let’s move on.
The default timeout to check for new file changes is usually about one second. However, there are cases where we intend to delay the time it takes for Nodemon to check for file changes for a longer period.
We can do this by using the --delay
command. See the code sample below:
nodemon --delay 3000ms index.js
3000ms
is the delay value in milliseconds (this could also be in seconds) before our app restarts. Therefore, Nodemon will only restart the web server when that time elapses.
We can specify extensions to watch when there are file changes in directories or sub directories.
For example, we can specify our own list with the -e
(or --ext
) command line argument. See the code sample below:
nodemon -e njk
By default, Nodemon looks for files with the
.js
,.mjs
,.coffee
,.litcoffee
, and.json
extensions.
Apart from Node programs, Nodemon can also be used to monitor other programs. Based on the file extension, Nodemon will go ahead to execute the command.
For more details on running non-Node code, readers can check the documentation.
While Nodemon is running, we can manually restart our application. So instead of stopping and restarting Nodemon, we can just type
rs
and press enter, and Nodemon will restart the server or the running process for us.
We can tell Nodemon not to write to the stdout
by specifying a set of rules to do so. More details can be found in the documentation.
Nodemon, with the help of the nodemon.json
config file, can have a default executable declared. This will in turn allow us watch for changes that are not node.js
specific.
To do so, we can make use of the execMap
property. Note that it is generally recommended to use the global nodemon.json
to add an execMap
option to our config. You can read more details in the documentation.
We can add a notification when Nodemon restarts. Also, an action can be triggered when an event occurs. More details about this can be found in the documentation.
As of version 1.0.0, Nodemon can work as a required module in Node.js. By doing this, we can then extend its functionality and make it suit our other needs.
More details can be found in the documentation here.
In Node.js, Nodemon can be likened to a magic wand because of its ability to automatically restart a web application upon file changes. In other words, Nodemon simply eliminates the need for programmers to manually stop and restart their application source code in development repeatedly after every change is made.
It is a utility tool that makes rapid development less cumbersome. As a tool, it continuously monitors your Node.js application and quietly waits for file changes before automatically restarting the server. To add some more extra configurations, we can make use of a nodemon.json
file.
The file can be used to add some extra configurations to our application to allow us monitor multiple directories, ignore files, and delay restarting amongst others. For more details and “gotchas” on how Nodemon works and possible work arounds for issues, readers can also refer to the FAQ.
The FAQ documentation also contains some other tips and tricks we can refer to, including other use cases for Nodemon not mentioned or covered in this tutorial.
For example, clearing the console on restart, restarting Nodemon on .env
file change, overriding the default ignore rules, and so on. A link to the documentation is available here on GitHub.
Thanks again for reading. Please drop any comments or questions you have in the comment section below, or reach out to me on Twitter.
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.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.