Using Node.js in Production (Part I)

How to deploy Node.js applications into production environments and have a robust pipeline to go from development to deployment

Ryan Dsilva
JavaScript in Plain English

--

This is Part 1 of the series where we are going to look at PM2 as a process manager help scale to our application.

Many of us use Node.js as our runtime of choice while building backend servers due to a plethora of reasons — It’s fast, uses JavaScript and the npm ecosystem is unmatched. But most of us leave our applications using just the default configuration, running —

node server.js

While this is easy, it’s not scalable due to the single-threaded nature of Node.js. In most cases, the deployment system/virtual machine will have more than 1 usable thread, and running the default command will result in suboptimal usage of the available resources as only one thread is used to run this Node.js process. Ideally, you’d want to run as many Node.js processes as the number of cores/threads available to you (for a monolith application).

This is where PM2 comes to the rescue. PM2 is a production process manager for Node.js applications. Using PM2 has a lot of advantages — running multiple Node.js instances, advanced monitoring and logging, graceful restarts, etc.

PM2 — Production-grade process manager for Node.js

We’ll be using a dummy Node.js application that I built for the purpose of this demonstration. You can find the initial state before any PM2 configuration, here. The master branch will always hold the latest state of the project depending on when you’re reading this, so to find the initial code, switch to the initial branch. For this tutorial, we’ll be working in the pm2 branch.

Firstly, we need to install PM2 as a global dependency. For that:

npm i -g pm2@latest

Some people might have to run this command using sudo.

Also, another thing that you might want to do is to have PM2 load during system startup and depending on which OS you are on, things might differ. But luckily, PM2 has you covered for that too:

pm2 startup

This will print out a command you need to run that will enable PM2 to load on system startup. This command would require you to use sudo

Now, we can already run multiple instances of our Node.js application just using PM2 from the command line, specifying the configuration in the arguments —

pm2 start server.js -i 0

What this command will do is startup as many Node.js processes as the number of threads/cores available to use. Optionally you can customize the number of processes by replacing the 0 with any number you’d like.

Useful additional commands you should know include —

# List all processes
pm2 list
# Monitoring
pm2 monit
# Stop All Processes
pm2 stop all
# Delete All Processes
pm2 delete all
# Start All Processes
pm2 start all

While this works pretty well, I like a more customized approach to this and we can achieve that we’ll use a file called ecosystem.config.js and we can easily generate a boilerplate for that using — pm2 ecosystem
We are not going to be using the deploy section of that file for this example, so we can delete that. We’re going to changeecosystem.config.js to look something like this —

Okay, so that’s a lot of terms to explain, but we’ll get through this. The apps list contains the list of all the Node.js applications that we want to run, which in our case is just the one application we have. Let’s look at the properties of the object inside the appslist.

  • name refers to the name of the application with which PM2 will reference it. This will show up in the processes list.
  • script is the starting point of the application, which is the server.js file for us.
  • instances refers to the number of Node.js processes that PM2 spawns, this can be any number. Setting it to max spawns processes equal to the number of threads/cores.
  • exec_mode is the property that allows our Node.js application to scale across CPU cores by setting it to cluster mode. By doing this essentially we’re implementing ‘Load Balancing’ to improve the performance of our application.
  • The next object is the environment variables for the application and we can have as many of these as we need, each starting with env_*. In this case, we have two, the PORT and NODE_ENV.

This is all the config we need to run our application. Now let’s modify our start script in the package.json file to use PM2.

start: "pm2 start ecosystem.config.js --env production"

Congratulations! With this, you now have your Node.js application scaled up to use all available CPU cores along with additional functionality like graceful shutdown/restart, monitoring, etc.

Thank you so much if you made it this far and I hope this was useful. Please share this and any feedback is appreciated. See you in Part 2.

--

--

Full Stack TypeScript/JavaScript Developer | Flutter | Deep Learning | Grad Student — Purdue University