Side note: Get alerted when your Node.js app goes down
Head over to Better Stack and start monitoring your endpoints in 2 minutes.
PM2 is a renowned open-source process manager tailored for Node.js applications. It acts as a guardian, streamlining deployment, overseeing logs, monitoring resources, and ensuring minimal downtime for every application it manages.
This article will introduce you to the key features of PM2 and help you leverage it for deploying, overseeing, and scaling your Node.js applications effectively in a production environment.
Before proceeding with this tutorial, ensure that you have a recent version of Node.js and npm installed on your machine.
Head over to Better Stack and start monitoring your endpoints in 2 minutes.
In this guide, we'll explore various functionalities of PM2 using a sample Node.js application. If you have your project, you're welcome to use it as you follow along. If not, let's get started by cloning the demo app repository:
Once cloned, navigate into the project directory and set up its required dependencies:
This application fetches a humorous dad joke from the ICanHazdadjokes API and displays it on a webpage. To see it in action, initiate the server using:
With the server up and running, open your browser and head to http://localhost:3000. Here's what you can expect to see:
Having set up the demo app, we'll transition to installing PM2's npm package in the next section.
To harness the power of PM2 for managing your Node.js applications, you'll first need to install its npm package as follows:
Go ahead and confirm the version you have installed through the following command:
Here's the expected output:
Interestingly, your PM2 installation actually provides four distinct executables:
pm2: The primary PM2 binary.pm2-dev: A development tool akin to
nodemon that auto-restarts the
Node.js process during development.pm2-runtime: A seamless alternative to the node command, tailored for
containerized environments.pm2-docker: Essentially an alias for pm2-runtime.In the sections ahead, we'll delve into the specific applications of each of
these executables. But for now, let's focus on establishing a foundational
development workflow using the pm2-dev binary in the next step.
While PM2 is primarily renowned for its usefulness in production, it can also
serve you during the development phase through the pm2-dev binary. When you
kickstart your application using pm2-dev, it monitors the current directory.
Your application gets a swift restart if there are any changes in the directory
or its subdirectories.
To set things in motion, first ensure that any previously running instance of
your server is terminated with Ctrl-C. Then launch your server in development
mode:
You should observe the following output:
At this point, changing any file in the dadjokes directory will cause the
server to restart. Try it out by modifying your server.js file as shown below.
Change the title property from 'Random Jokes' to 'Random Dad Jokes' and save
the file:
Now, shift your attention to the terminal where your development server is active. You'll notice an output indicating PM2's awareness of the change and its subsequent action to restart the server:
For a deeper dive into pm2-dev and its capabilities, use the --help flag.
It'll unveil the available options to tailor pm2-dev to your needs. Up next,
we'll transition to the core features of the primary pm2 binary.
When it's time to shift from development to production, the pm2 start command
is one to use. First, ensure you've terminated any running development server
with Ctrl-C. Then, to launch your application in a production setting, use:
You should see the following output:
This table confirms the successful background launch of the dadjokes
application. If your terminal window is compact, you might see fewer columns, so
consider expanding it for a comprehensive view.
Here's a breakdown of the table columns:
id: A unique identifier assigned by pm2 to the application.name: The application's name. If the --name flag isn't specified, it
defaults to the entry file name (in this case, server.js).namespace: Allows for batch operations (like start/stop/restart) on a group
of apps.version: The version number sourced from the app's package.json.mode: Can be either fork or cluster. It directs pm2 to utilize the
child_process.fork
or the cluster API.pid: The process's unique identifier.uptime: Duration since the application's launch. ↺: Counts the number of
application restarts. status: Current application status. cpu: Percentage
of CPU usage. mem: Memory consumption. user: The username of the
individual who initiated the application. watching: Indicates if pm2 is set
to auto-restart the app upon detecting file changes in the directory or its
subdirectories. This is controlled by the --watch option.At this point, you can visit http://localhost:3000 in your browser and everything should work just fine as before.
If you need your application to connect to various services (such as databases,
caches, etc) on start up, you can use the --wait-ready flag which instructs
PM2 to await a ready signal from your application before marking it as
"online". Here's how to implement this:
After integrating the highlighted lines into your application, you'll need to
delete the current instance and restart it, this time using the --wait-ready
flag:
By default, if the ready signal isn't received, PM2 will wait for three
seconds before designating your application as online. If you wish to adjust
this duration, you can use the --listen-timeout flag followed by the desired
timeout in milliseconds:
Up next, we'll delve into how you can monitor your application's resource consumption and other pertinent metrics using PM2.
With your application in motion, PM2 offers a suite of subcommands—list,
show, and monit—to help you monitor its performance. To get an overview of
all active applications on your server, use:
You should observe the following output:
This command provides a snapshot of each application's status, uptime, memory usage, and more. If you have multiple applications running, you can sort them based on specific metrics:
As in:
For a more detailed look at a specific application, use the pm2 show command
followed by the application's name or id:
[s/t]
For a live dashboard displaying metrics, metadata, and application logs, use:
Head over to Better Uptime start monitoring your endpoints in 2 minutes
PM2's auto-restart capability is a boon for ensuring
application uptime. You can also restart your
application manually through the pm2 restart command as follows:
Notice that the restart column (↺) has been incremented to 1, indicating that
the application has been restarted once.
PM2's default behavior is to restart your application even if it exits
intentionally. For instance, triggering the /graceful-shutdown route in the
dadjokes application will gracefully shut it down by calling process.exit(0):
On the other hand, accessing the /crashme route simulates an application
crash:
After these actions, executing the pm2 list command will show the restart
count has risen to 3, yet the application status remains online:
Currently, PM2 doesn't offer the flexibility to adjust restart behavior based on
an application's exit code. Although the --stop-exit-codes flag is
documented, it seems
non-functional in the recent versions. This limitation is being tracked in an
open GitHub issue.
In the next step, you will configure other auto-restart strategies through the PM2 configuration file.
PM2 employs an ecosystem.config.js file to consolidate
configuration settings
for one or more applications. To generate this file in your project directory,
use:
Upon execution, you should see:
Edit the ecosystem.config.js file and update the name and script fields to
match your application:
With this configuration, you can manage all declared applications:
Let's now delve into advanced restart strategies:
PM2 can restart an application upon reaching a memory limit, preventing
potential "heap out of memory errors". Configure this using the
max_memory_restart option:
This restarts the dadjokes application if memory usage surpasses 1 Gigabyte. You
can also configure the max_memory_restart option in Kilobyte (K), and Megabyte
(M).
PM2 can restart applications based on a cron schedule. For daily restarts:
To learn and test the cron syntax, consider using the crontab guru editor.
You can introduce a delay before PM2 restarts an application using the
restart_delay option:
Instead of setting a fixed delay before restarting the application, you can use
the exp_backoff_restart_delay option to to raise the time between restarts up
to 15 seconds incrementally. The initial delay time set through this option will
be multiplied by 1.5 after each restart attempt.
With the above in place, the first restart attempt will be delayed by 100ms, second restart 150ms, then 225ms, 337.5ms, 506.25ms, and so on. This delay is reset to 0ms if the application remains online for over 30 seconds.
PM2 provides a max_restarts option for configuring the maximum number of
unstable restarts before the application is considered to have encountered an
unrecoverable error. This lets you prevent your application from constantly
dying and restarting, which may waste resources.
You can also specify an unstable restart through the min_uptime option. This
allows you to specify the amount of time before your application is considered
"online":
Once an application has reached the maximum number of restarts, it will display
an errored status. Your intervention will be required before the app can be up
and running once again.
To turn off automatic restarts entirely, set the autorestart option to
false:
Now, go ahead and integrate these strategies into your ecosystem.config.js:
Remove the existing dadjokes instance:
Then, relaunch it using the configuration file:
In the next section, you will discover how to start your Node.js application automatically even after a system reboot.
In the last section, we explored methods to keep your application resilient
against unexpected crashes. In this segment, we'll delve into how to set up a
Node.js application to autostart after system reboots or crashes using PM2 and
Systemd on Linux. Although PM2 is
compatible with various init systems, including upstart, launchd, openrc,
rcd, and systemv, this guide focuses on Systemd.
Begin by generating an init script for your system. This script will initiate the pm2 daemon during system startup, which in turn will launch any saved applications:
The output should resemble:
Go ahead and run the generated command shown above to configure the Systemd startup script:
A successful command will yield:
If you encounter an error, it might indicate that the pm2 service file was
created but couldn't be enabled. In such cases, manually enable the service:
To ensure that PM2 automatically starts any saved processes upon system boot, save your PM2 process list:
Now, PM2 is set to launch saved processes on system boot automatically, and you
can update this list anytime with pm2 save. Test this by rebooting your system
and running pm2 list afterward. If any issues arise, use the following command
to launch all applications:
To deactivate the startup script, employ the pm2 unstartup command. It's a
good practice to do this whenever you upgrade Node.js, ensuring that the
subsequent pm2 startup uses the updated Node.js binary.
If you need to disable the startup script, use the pm2 unstartup command. You
should always do this after upgrading your Node.js version so that when you run
pm2 startup again, it'll generate a startup configuration that uses the latest
Node.js binary.
At this point, you've learned all the ways PM2 ensures your application's resilience against external disruptions like system reboots. For continuous monitoring of your application's online status, consider implementing uptime monitoring checks for timely notifications on server availability and other related issues.
PM2 offers the stop and delete commands to halt an application and expunge
it from the process list, respectively. These commands can target specific
applications by their names, ids, namespaces, configuration files, or you can
use the all keyword to target every application.
To halt all applications defined in the ecosystem.config.js file, use:
When you pass the all keyword, it causes the delete subcommand to act on all
the applications in the list:
After deleting your application, you may need to run pm2 save to update
process list dump file.
To guarantee a smooth shutdown when employing the restart, stop, reload,
or delete commands, it's crucial to catch the SIGINT or SIGTERM signals.
This ensures that any essential cleanup tasks are executed before the
application terminates, such as processing all current requests and releasing
resources like files and database connections.
Below is a sample that stops the server from accepting new connections when the
SIGINT and SIGTERM signals are detected, and then terminates the process:
PM2 automatically archives logs generated by your application in the
$HOME/.pm2/logs directory. Logs directed to the standard output are stored in
the <app_name>-out.log file, while logs directed to the standard error are
stored in the <app_name>-error.log file.
Within the ecosystem.config.js file, you can define the error_file and
out_file options to specify custom locations for the application's error and
output log files:
To ensure that your application log files are rotated before they get too large, install the pm2-logrotate module as shown below:
Afterward, when you run pm2 list, you should see a new "Module" section like
so:
By default, the pm2-logrotate module rotates log files once they exceed 10
megabytes. It retains up to 30 rotated files and deletes older ones. Backup
files are not compressed by default. You can adjust these settings and more by
referring to the module's documentation, or you use
logrotate to handle
log file rotation instead.
The pm2 logs command may come in handy in development for displaying incoming
application log entries in real time:
To explore all available options for the logs command and customize its
output, use:
PM2 offers a cluster mode, enabling networked Node.js applications to harness the full power of the host's CPUs without any code changes. This results in launching multiple application instances (based on your machine's CPU count) on the same port, effectively distributing incoming workloads among them and enhancing performance.
Internally, PM2 relies on Node.js's cluster module to spawn child processes that share the server port. Your application should be stateless to maximize the benefits of PM2's cluster mode. This ensures that any reference to past transactions is managed through a shared, stateful medium like a database or cache.
To initiate your application in cluster mode, first remove it from the process
list. Then, specify the number of workers via the instances option and set the
exec_mode option to cluster:
Then, use the start command with the -i flag:
Here, max instructs PM2 to spawn as many workers as there are CPU cores. While
you can specify a particular number, it's not recommended to exceed the number
of CPU cores, as it can lead to resource contention and performance issues.
A common practice is to spawn one worker less than the total CPU cores. If your
server has four cores, you'd typically spawn three workers. Achieve this in PM2
by setting instances to -1:
Starting the application will yield:
You'll notice that the application launches in cluster mode, not fork as
before. The number of workers corresponds to your machine's CPU cores.
Using cluster mode ensures balanced request handling across workers. The
NODE_APP_INSTANCE environment variable can distinguish between processes,
handy for operations exclusive to one process.
Modify the /joke endpoint in your server.js file as shown below:
Restart the application through the command below:
Afterward, send a handful of requests to the /joke endpoint and view the logs:
You'll observe that a number prefixes each log entry. This number is the id
for each worker process, and it can be accessed in the application code via
process.env.NODE_APP_INSTANCE as demonstrated earlier. Notice how we can
execute some code on process 0 only even though requests were sent to all
three worker instances (on our test machine, could be more or less on yours).
An advantage of cluster mode is zero-downtime reloads in production using
pm2 reload. This restarts processes sequentially, ensuring continuous
availability. Conversely, pm2 restart halts and restarts all processes
simultaneously, causing brief downtime.
PM2 also offers dynamic scaling with the scale command. For instance, to add two workers:
Or, to set a specific number of workers:
This flexibility ensures your application can adapt to varying workloads quickly and efficiently.
PM2 provides an
integrated deployment system
to facilitate deploying your application to one or multiple remote servers. To
set this up, modify your ecosystem.config.js file as follows:
Here's a breakdown of the production object properties:
user: The username for authentication on the remote server.host: An array of IP addresses of the remote servers.ref: The git branch and remote to deploy, e.g., origin/master.repo: The git repository's remote URL (HTTPS or SSH).path: The directory on the remote server where the repository will be
cloned.post-setup: Commands or scripts to run post cloning.post-deploy: Commands or scripts to run after deployment.Before deploying to the specified host servers, ensure each has PM2 installed and the necessary permissions to clone the Git repository (e.g., the correct SSH key setup). Once set up, initiate the server provisioning with:
Here's the output to expect if everything goes well:
If you encounter an error, it's likely SSH-related, preventing PM2 from
accessing the remote server or Git repository. Start your investigation by
ensuring that the git clone <your_git_repo_url> command works on the remote
server. For troubleshooting PM2 deployments, refer to this
guide.
After successful provisioning, deploy the application:
A successful deployment will show:
Logging into your remote server and executing pm2 list will confirm the
application's deployment and operational status. Additionally, you can run
commands on each remote server without logging in using the pm2 deploy
command. For instance, to reload the dadjokes application on all remote
servers, run:
A successful reload will display:
For a deeper dive into deployment commands and hooks, consult the relevant PM2 documentation.
Note that while PM2 provides a
Docker integration
through its pm2-runtime command, the
general recommendation
is to forgo using PM2 if you're deploying your Node.js application with Docker.
PM2 keeps your Node.js applications running, but you still need external monitoring to know when your services become unreachable or start failing. Better Stack provides comprehensive uptime monitoring that works alongside PM2 to give you complete visibility into your application's availability.
Better Stack monitors your endpoints every 30 seconds from 171 locations worldwide, instantly alerting you via Slack, SMS, phone calls, or email when issues occur. This external monitoring catches problems PM2 can't detect—like network issues, DNS failures, load balancer problems, or when your entire server goes down.
You can create HTTP, ping, keyword, or port monitors for your PM2-managed applications. Configure SSL certificate expiration checks, set custom headers for authentication, and use keyword monitoring to verify your app returns the correct response. Better Stack automatically tracks response times, uptime percentages, and provides detailed incident timelines.
If you're running scheduled jobs or workers with PM2, use Better Stack's heartbeat monitoring to verify they execute successfully. Your cron jobs or workers ping Better Stack when they complete—if the ping doesn't arrive within the expected interval, you get alerted immediately. This is perfect for monitoring database backups, data processing jobs, or any scheduled tasks managed by PM2.
Getting started takes just minutes: sign up for a free account, create monitors for your PM2-managed services, and configure alert channels.
PM2 is a powerful tool for managing and maintaining Node.js applications, offering several features to streamline development and production workflows. While we've covered many of its capabilities in this guide, a vast array of features is still waiting to be explored.
Whether you're looking to integrate PM2 with Docker, run it without a daemon, or set it up with NGINX as a reverse proxy, the possibilities are vast. The PM2 documentation should be your next stop to gain insights into those topics and many others.
Note that the complete source code from this tutorial is available on the prod branch of the dadjokes GitHub repository. It is a practical reference and a starting point for your projects.
Thanks for reading, and happy coding!
We use cookies to authenticate users, improve the product user experience, and for personalized ads. Learn more.