DEV Community

Cover image for Configuring nodemon with TypeScript
Cole Gawin
Cole Gawin

Posted on

Configuring nodemon with TypeScript

Originally published on the LogRocket blog.

nodemon is a CLI for Node.js that makes JavaScript development much quicker by restarting an execution process when a file is updated. For example, if you have a project with an index.js file that you want to quickly test and iterate on, you can run nodemon index.js, and a new Node.js execution process will begin for index.js, restarting whenever a file in the project is updated. Simple, right?

Well, the simplicity offered by nodemon diminishes both as you introduce TypeScript into your project, and as the complexity of your project grows. But fear not! In this article, we’ll review three methods of configuring nodemon, each of which offers different features and functionalities that can meet the needs of your TypeScript project.

We will also review three nodemon alternatives with extra features and more customizability, if you are looking for alternatives to nodemon that will better fit your project's requirements. Since each option has its own pros and cons, we will discuss whether or not each option will suit the needs of our project, and if not, which option is a better choice.

Method 1: No-config workflow

As of v1.19.0, nodemon has built-in 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 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 a version of nodemon ≥1.19.0 to be installed. In addition, ts-node must be installed in your project. Since both of these packages will likely only be used during development, they should be installed as devDependencies.

yarn add --dev nodemon ts-node
Enter fullscreen mode Exit fullscreen mode

Once both of these dependencies are installed, you can pass a TypeScript file to nodemon as you would a JavaScript file.

npx nodemon ./main.ts
Enter fullscreen mode Exit fullscreen mode

Advantages and disadvantages

This method is by far the most simple, as it requires 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 just the default tsc TypeScript compiler that is used by ts-node, and still others will require more advanced configuration; if this scenario describes your needs, proceed to method two.

Method 2: Manual configuration

The built-in nodemon TypeScript runner provides a method to get up and running with minimal setup: manual configuration.

If your project requires more flexibility in how your files are executed, nodemon allows users to create a configuration file to meet a project's exact specifications. By using a custom configuration file, you 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 about which 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
Enter fullscreen mode Exit fullscreen mode

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

Inside the execMap object, create a new property for ts files. The value of this property should be whatever command you want to run when executing your TypeScript files. For example, you can set it to ts-node, or any other execution script or command.

{
    "execMap": {
        "ts": "ts-node"
    }
}
Enter fullscreen mode Exit fullscreen mode

Voilà, nodemon is now configured to run a custom command for TypeScript files. When you 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).

Bonus tip: if you want to pass the filepath elsewhere in the command (i.e., not as the final argument), type {{pwd}} where the filepath should be placed in the command. For example, if your execMap command for .js files is node {{pwd}} && echo "Hello world", then calling nodemon index.js will run node index.js && echo "Hello world".

Advantages and disadvantages

Using a custom nodemon configuration file opens up a lot of flexibility that many projects require. There are a lot of settings that you can configure, as explained by the nodemon documentation.

To that extent, this method should only be used in cases where the first method will not meet your project's requirements. If your project only needs your TypeScript files to be compiled and ran, then the inbuilt nodemon TypeScript support with ts-node (method one) will likely be the best option for your project.

If your project happens to need even more customization, consider method three.

Method 3: Custom execution command

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 the use of an outside tool to bootstrap or execute your project.

Whereas methods one and two offer ways to execute a single file, this method will offer a way to execute a single command, thereby offering the most flexibility of these methods.

In your package.json file, create a start script. This will serve as the command that 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"
Enter fullscreen mode Exit fullscreen mode

This passes the start script as the executable command to run for your project by nodemon.

Bonus tip: you can make the full nodemon command (i.e., nodemon --exec "yarn start") a dev script, such that calling yarn dev will run nodemon with your custom execuction command.

Advantages and disadvantages

Although this method offers the most flexibility in terms of what can be run, it does negate 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 are better suited for your project's needs.


What are some alternatives to nodemon?

nodemon is certainly a powerful tool for rapid development with Node.js. However, there are also numerous alternatives that may be better suited for your 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.

Alternative 1: ts-node-dev

In the first method, we discussed how nodemon uses ts-node to compile and run TypeScript files. [ts-node-dev](https://github.com/wclr/ts-node-dev) combines the file-watching capabilities of nodemon with the TypeScript support from ts-node into a nodemon-like service that is specifically tailored 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
Enter fullscreen mode Exit fullscreen mode

Then, to run your file and restart on file changes, run:

ts-node-dev --respawn index.ts
# or
tsnd --respawn index.ts
Enter fullscreen mode Exit fullscreen mode

Replace index.ts with the entry file to your project.

Advantages and disadvantages

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 your project.

Alternative 2: pm2

[pm2](https://github.com/Unitech/pm2) is a battle-tested and production-ready process manager for Node.js programs that is loaded with numerous features and configuration options. It is used to manage 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 all of these features, pm2 offers an auto-restart functionality that will restart your program when a file is changed.

To get started with pm2, install it globally on your system.

npm install pm2 -g
Enter fullscreen mode Exit fullscreen mode

Next, we will have to do a little bit of configuration. 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
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

This will create a new app called "TSServer" that will run ts-node index.ts. Finally, run:

pm2 start ecosystem.config.js --only TSServer --watch
Enter fullscreen mode Exit fullscreen mode

This will run the TSServer app and restart on file changes with the watch argument. A fancy table with information about your application should print to the terminal, and a column titled Watching should read Enabled for your application. This application will now run in the background until you call pm2 stop TSServer.

Advantages and disadvantages

As previously stated, pm2 is jam-packed with exciting features that are incredibly useful for large production applications. However, for this reason, pm2 may very well be overkill for your project.

If you are just looking for a simple way to restart TypeScript projects, this method will likely not be the best choice for your project and you should consider other alternatives or nodemon methods.

Alternative 3: DIY file watcher with Parcel

Sometimes, the best way to do something is it do it entirely by yourself from scratch.

As we have seen in all of the previous methods and alternative, there is always a potential negative or drawback to using one option instead of another. You can avoid these limitations by creating a file watcher from scratch, and even learn 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()
Enter fullscreen mode Exit fullscreen mode

Another benefit of this method is that you can actually write your entire file watcher in TypeScript! To run your file watcher, simply run your file with ts-node.

ts-node runner.ts
Enter fullscreen mode Exit fullscreen mode

Advantages and disadvantages

This method, by far, offers the most customizability, since you are creating the file watching process yourself. You can spawn a different child process if needed, or spawn multiple, and you can run any other JavaScript/TypeScript code as needed when a file is updated.

However, as this is a DIY solution, it is your own responsibility to upkeep and maintain the runner, whereas this is done for you by teams of knowledgeable open source developers for all of the other options provided in this article. As long as you know what you are doing, however, this alternative option should certainly not be overlooked!

Conclusion

There are numerous ways in which nodemon can be configured to fit your project’s needs and requirements. However, if none of those methods work for you, there are also ample alternatives that may offer different advantages over nodemon for your project. I hope you have found a method in this article that will suit your specific use case.

Top comments (1)

Collapse
 
ivanzm123 profile image
Ivan Zaldivar • Edited

Excellent article buddy!. Another simpler way to configure nodemon would be the following:

Step 1: Create a nodemon.json file in root project.

{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/**/*.spec.ts", "node_modules"],
  "exec": "ts-node ./src/index.ts"
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Update package.json file.

{
  "name": "some-package-name",
  "scripts": {
    "start:dev": "nodemon"
  }
}
Enter fullscreen mode Exit fullscreen mode