Editor’s note: This article was last updated by Yan Sun on 27 February 2024 to cover integrating environment variables with nodemon, as well as advanced nodemon configuration options like using the --ignore option to ignore functions or monitoring multiple directories with the --watch option.
nodemon is a CLI for Node.js that speeds up JavaScript development by restarting an execution process when a file is updated. For example, if we have a project with an index.js file that we want to test and iterate on quickly, we can run nodemon index.js. A new Node.js execution process will begin for index.js, restarting whenever a file in the project is updated. Simple, right?
However, when TypeScript is introduced into the project and our project becomes more complex, the simplicity offered by nodemon diminshes. But don’t worry! In this article, we’ll explore three ways of setting up nodemon, each with different features and functionalities that can meet the needs of our TypeScript project.
If you are looking for alternatives to nodemon that will better fit the project’s requirements, we will also review three nodemon alternatives with extra features and more customizability. As each option has pros and cons, we will assess their suitability for our project to identify the best choice.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
As of v1.19.0, nodemon has inbuilt support for TypeScript files with help from ts-node that requires no manual configuration. By default, nodemon uses the node CLI as an execution program for running JavaScript files; for TypeScript files, nodemon uses ts-node as the execution program instead.
ts-node is a TypeScript execution engine that compiles and runs TypeScript files. ts-node serves as a drop-in replacement for the node CLI, so the same arguments can be passed to the ts-node CLI as the node CLI.
This method requires installing a version of nodemon ≥1.19.0. In addition, ts-node must be installed in our project. Because both packages will only be used during development, they should be installed as devDependencies. devDependencies are dependencies that are used during development, such as build tools, but are not necessary for the application’s runtime:
yarn add --dev nodemon ts-node # or use npm npm install --save-dev nodemon ts-node
Once both dependencies are installed, we can pass a TypeScript file to nodemon as the following command, which will monitor changes in the main.ts file and restart the application accordingly:
npx nodemon ./main.ts
This method is a simple approach, requiring minimal setup. It’s built into nodemon itself, so all that is required is installing the necessary packages.
However, this method falls short in terms of flexibility and customization. Many projects require more than the default tsc TypeScript compiler used by ts-node, and others may require advanced configurations. If this resonates with our project requirements, consider proceeding to method two.
The inbuilt nodemon TypeScript runner allows us to customize the behavior of the development environment to specific project needs using configuration files.
If the project requires more flexibility in how the files are executed, we can create a nodemon configuration file to meet the project’s exact specifications. By using a custom configuration file, we can reap the maximum benefits of nodemon’s flexibility and take advantage of all of its offered settings.
The specific setting we will be configuring is execMap, or execution map. This setting informs nodemon, with executables, or commands to run for different file types. For now, we’ll go over how to set up an execution map specifically for TypeScript files.
To create a configuration file, make a new file in your project’s root directory named nodemon.json:
touch ./nodemon.json
In the nodemon.json file, create a new JSON object with an execMap property. The value of the execMap property should be an object:
{
"execMap": {}
}
Inside the execMap object, create a new property for ts files. The value of this property should be the command to run when executing the TypeScript files. For example, we can set it to ts-node, or any other execution script or command:
{
"execMap": {
"ts": "ts-node"
}
}
Voilà, nodemon is now configured to run a custom command for TypeScript files. When we call nodemon with a TypeScript file (i.e., nodemon index.ts), nodemon will find the command in the execMap that correlates to .ts files and then run that command, passing the file as the final argument (i.e., ts-node index.ts).
To convey the file path within the custom command in execMap , use {{pwd}} where the file path needs placement. For example, if the execMap command for .js files is node {{pwd}} && echo "Hello world", then calling nodemon index.js will result in running node index.js && echo "Hello world".
Using a custom nodemon configuration file opens up a lot of flexibility that many projects require. We can configure many settings, as explained by the nodemon documentation.
To that extent, this method should only be used in cases where the first method does not meet the project’s requirements. If our project only needs TypeScript files to be compiled and run, then the inbuilt nodemon TypeScript support with ts-node (method one) will likely be the best option for the project.
If our project happens to need even more customization, consider method three.
nodemon shines as a tool to help run and restart the execution of a single file when any file in a project is updated. However, not all projects have a single entry point; that is, many modern projects require an outside tool to bootstrap or execute our project.
While methods one and two offer ways to execute a single file, this method provides a way to execute a single command, thereby offering the most flexibility.
In the package.json file, create a start script. This command will be run and restarted by nodemon when a file changes.
To execute this command with nodemon, run:
nodemon --exec "yarn start" # or nodemon --exec "npm run start"
This passes the start script as the executable command for the project by nodemon.
We can make the full nodemon command (i.e., nodemon --exec "yarn start") a dev script. Then, we can call yarn dev to run the nodemon custom command.
Although this method offers the most flexibility in terms of what can be run, it negates nodemon’s most notable feature: (re)running the execution of a single file when a file in the project is updated.
Before choosing this method, consider whether methods one or two suit the project’s needs.
Environment variables are dynamic configurations for our application in different environments, such as development or production. dotenv is a popular package that allows us to manage environment variables in a separate file, enhancing organization.
When we use nodemon together with dotenv, it will streamline our development by managing configurations and allow continuous testing without manual restarts.
First, let’s install the dotenv package:
npm install --save-dev dotenv #or use yarn yarn add --dev dotenv
Then, we must create a .env file at the root of our project directory:
PORT=3000 NODE_ENV=development
We can use the --require(-r) option to preload the dotenv config file. To demonstrate the use of the dotenv config file, let’s add the line below to the index.ts:
console.log(`environment: ${process.env.NODE_ENV}, port:${process.env.PORT}`);
Run the following command to display the values of the environment variables in the console:
nodemon -r dotenv/config index.ts
Alternatively, we can add the -r option to the nodemon.json config file as below to skip the -r option when running the nodemon command:
{
"execMap": {
"ts": "ts-node -r dotenv/config"
}
}
Now, when we run nodemon, it will pick up changes in TypeScript files and reload your application with the specified environment variables.
nodemon offers advanced configuration options, allowing us to customize behavior to specific project requirements. Here are some of the common options:
--ignore)--ignore option. This is handy when certain files or folders should not trigger a restart. For example, nodemon will ignore the lib/app.js file when running the following command:
nodemon --ignore lib/app.js
--watch)--watch option to include additional directories:
nodemon --watch app --watch libs index.ts
With the above command, nodemon will monitor the “app” and “libs” directories for changes.
**--ext**).js, .mjs, .coffee, .litcoffee, and .json extensions. To define a custom list of file extensions, we can use the --ext option:
nodemon -e ts,js,conf
In this example, a change of files with extensions of ts, js, and conf will trigger nodemon to restart.
--delay)---delay option.For example, the following command runs nodemon with a delay of 10 seconds before restarting the application:
nodemon --delay 10 index.ts
nodemon.json config file. In the following example, we define a restart event to clear the console screen upon nodemon restarts:
"events": {
"restart": "clear"
}
Below is the list of the nodemon events:
start: The child process has startedcrash: The child process has crashed (nodemon will not emit exit)exit: The child process has cleanly exited (i.e., no crash)restart: The child process has restartedconfig:update: nodemon’s config has changedLet’s look at some common issues of using nodemon, and how to address them.
"Command Not Found: nodemon"If we encounter the "command not found" error, it means nodemon isn’t installed correctly. To fix the issue, we can either install nodemon globally or locally as the project’s dev dependencies.
To install nodemon globally, follow the command below:
# install nodemon globally npm install -g nodemon # yarn yarn global add nodemon
To install nodemon as a project dev dependency, use the following command:
# install nodemon as a development dependency npm install --save-dev nodemon
Then, add the following script command into the package.json file. We should be able to run nodemon by running npm run start:
"start": "nodemon index.ts"
ts-node and nodemonWhen using ts-node and nodemon together, we may experience a slow startup time due to TypeScript compilation. As ts-node transpiles TypeScript code to JavaScript during runtime, the initial compilation can be time-consuming, resulting in slower startup times, especially in larger projects or handling complex TypeScript files
Here are some tips to improve the performance.
--transpile-only flagThe --transpile-only flag skips type checking during compilation, which makes it much faster:
ts-node --transpileOnly
# or in nodemon.json
{
"execMap": {
"ts": "ts-node --transpileOnly"
}
}
swcswc (Speedy Web Compiler) is a TypeScript-compatible transpiler that is significantly faster. To use swc, we need to install it first:
npm install --save-dev @swc/core
Then add the following into tsconfig.json to enable swc:
{
"ts-node": {
"swc": true
}
}
nodemon is certainly a powerful tool for rapid development with Node.js. However, numerous alternatives may be better suited for our project.
In the next part of this post, we’ll consider three alternatives to nodemon: ts-node-dev, PM2, and a DIY file watcher built with Parcel.
ts-node-devIn the first method, we discussed how nodemon uses ts-node to compile and run TypeScript files. ts-node-dev combines the file-watching capabilities of nodemon with the TypeScript support from ts-node into a nodemon-like service tailored explicitly to TypeScript.
ts-node-dev interfaces directly with the TypeScript execution engine and compilation process to offer a more efficient system than nodemon for TypeScript files. ts-node-dev only reloads when changes are made to files that are a dependency of (i.e., imported by) the entry file. Additionally, ts-node-dev shares a singular compilation process between restarts to maximize efficiency and make restarts quicker.
To use ts-node-dev, first install it as a devDependency:
yarn add --dev ts-node-dev # or use npm npm install --save-dev ts-node-dev
Then, to run the file and restart on file changes, run:
ts-node-dev --respawn index.ts # or tsnd --respawn index.ts
Replace index.ts with the entry file to the project.
ts-node-dev is a great option for fast TypeScript development because it is more efficient than nodemon, and is made specifically for TypeScript.
However, while it does offer some level of configuration, ts-node-dev is arguably much less customizable than nodemon. It also does not restart on changes to static assets, which can be useful when serving images on a web server. Make sure to consider these downsides before choosing ts-node-dev for our project.
PM2 is a battle-tested and production-ready process manager for Node.js programs with numerous features and configuration options. It manages multiple Node.js applications and processes and comes with a load balancer to manage heavy applications with high amounts of queries.
PM2 supports hot reloading, application monitoring, and detailed process management. In addition to these features, PM2 offers an auto-restart functionality that restarts the program when a file is changed.
To get started with PM2, install it globally on our system:
npm install pm2 -g
Next, we will have to configure a little bit. Create a file named ecosystem.config.json, and enter the following contents:
module.exports = {
apps: [
{
name: "TSServer",
script: "ts-node",
args: "index.ts", // replace this with your project's entry file
}
]
}
This will create a new app called TSServer to run ts-node index.ts. Finally, run:
pm2 start ecosystem.config.js --only TSServer --watch
This will run the TSServer app and restart on file changes with the watch argument. A fancy table with information about the application should be printed on the terminal, and a column titled Watching should read Enabled for the application. This application will run in the background until we call pm2 stop TSServer.
As previously stated, PM2 is jam-packed with exciting features that are incredibly useful for large production applications. However, for this reason, PM2 may be overkill for our project.
If we are just looking for a simple way to restart TypeScript projects, this method will likely not be the best choice for the project, and we should consider other alternatives or nodemon methods.
Sometimes, the best way to do something is to do it entirely from scratch.
As we have seen in all of the previous methods and alternatives, there is always a potential negative or drawback to using one option instead of another. We can avoid these limitations by creating a file watcher from scratch and learning something along the way!
For this DIY file watcher, we will take advantage of the capabilities provided by the Parcel file bundler, which can be utilized for developing web apps or Node.js libraries.
Parcel exposes a JavaScript API to watch events in the bundling process. Each time a file is updated, the bundling process for our TypeScript project restarts. When the bundling process completes, we will spawn a child process that executes the bundled and compiled JavaScript file.
Here is an example of my DIY file watcher built with Parcel:
// make sure you have @parcel/core and @parcel/config-default
// installed as devDependencies
import {Parcel} from '@parcel/core';
import {spawn, ChildProcessWithoutNullStreams} from 'child_process';
let bundler = new Parcel({
entries: 'src/index.ts',
defaultConfig: '@parcel/config-default',
defaultTargetOptions: { distDir: `${process.cwd()}/dist` },
});
async function main() {
let cp: ChildProcessWithoutNullStreams;
await bundler.watch(() => {
cp?.kill()
cp = spawn("node",[`${process.cwd()}/dist/index.js`])
cp.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
})
cp.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
});
}
main()
Another benefit of this method is that we can write the entire file watcher in TypeScript! To run the file watcher, run it with ts-node:
ts-node runner.ts
This method, by far, offers the most customizability, as we are creating the entire file watching process. We can spawn a different child process if needed or spawn multiple, and we can run any other JavaScript/TypeScript code as needed when a file is updated.
However, unlike the other options in this article, this DIY solution requires maintaining the runner. If you’re confident in your abilities, this alternative option should certainly not be overlooked!
There are numerous ways in which nodemon can be configured to fit the project’s needs and requirements. However, if none of those nodemon methods works, there are also ample alternatives that may offer different advantages over nodemon for your project. I hope you found a method in this article that will suit your specific use case.
LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks, and with plugins to log additional context from Redux, Vuex, and @ngrx/store.
With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.
Modernize how you understand your web and mobile apps — start monitoring for free.

Examine AgentKit, Open AI’s new tool for building agents. Conduct a side-by-side comparison with n8n by building AI agents with each tool.

AI agents powered by MCP are redefining interfaces, shifting from clicks to intelligent, context-aware conversations.

Learn how platform engineering helps frontend teams streamline workflows with Backstage, automating builds, documentation, and project management.

Build an AI assistant with Vercel AI Elements, which provides pre-built React components specifically designed for AI applications.
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 now
3 Replies to "Configuring nodemon with TypeScript"
There is an option while using Typescript client:
tsc –watch
Or shortcut:
tsc -w
Hey Baptiste, thanks for your comment! The “tsc” command will only compile your typescript code and stops short of actually running or executing it. But if that’s all your project needs, it’s certainly a viable option!
This saved my life, thanks!
You have a typo in the pm2 sectgion, though: “Create a file named ecosystem.config.json”
This should have been config.js instead.
But thanks for putting everything together