$linuxjunkies
>

How to Run a Node.js App in Production with PM2

Deploy a Node.js application with PM2: process management, ecosystem config files, systemd startup integration, and structured log rotation.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • Node.js 18 LTS or newer installed and available in PATH
  • A non-root user account with sudo privileges
  • A working Node.js application with a defined entry point file
  • npm available (bundled with Node.js)

PM2 is a production-grade process manager for Node.js that handles automatic restarts, clustering, structured logging, and startup integration. It fills the gap between running node app.js in a terminal and a fully supervised service — without forcing you to write a systemd unit file by hand for every project.

Prerequisites

  • Node.js and npm installed (v18 LTS or newer recommended)
  • A working Node.js application with a defined entry point
  • A non-root user with sudo privileges
  • Basic familiarity with the terminal

Install PM2

Install PM2 globally via npm. This works the same across all major distros as long as Node.js is already present.

sudo npm install -g pm2

Confirm the installation:

pm2 --version

You should see a version string such as 5.3.x. If the command is not found, ensure /usr/local/bin or your npm global bin directory is in your PATH.

Start Your Application

The simplest way to launch an app is with pm2 start, passing the entry point and an optional name. The name is used in logs and management commands, so choose something meaningful.

pm2 start /var/www/myapp/index.js --name myapp

Check the running process list immediately after:

pm2 list

Output will look roughly like:

┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┤
│ 0  │ myapp  │ default     │ 1.0.0   │ fork    │ 12345    │ 5s     │ 0    │ online    │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┘

A status of online means the process is running. A status of errored means Node.js threw an uncaught exception at startup — check logs immediately (covered below).

Cluster Mode

For CPU-bound or high-concurrency apps, PM2 can fork one worker per logical CPU core using Node's cluster module, with zero code changes required:

pm2 start /var/www/myapp/index.js --name myapp -i max

Replace max with a specific integer (e.g., 4) to pin the instance count. Cluster mode only works correctly if your app is stateless or uses an external session store like Redis.

Use an Ecosystem File

Hard-coding flags on the command line does not scale. An ecosystem file is a versioned configuration that lives alongside your code, specifying entry points, environment variables, cluster settings, and more.

Generate a starter file:

cd /var/www/myapp
pm2 ecosystem

This creates ecosystem.config.js. Edit it to match your application:

module.exports = {
  apps: [
    {
      name: 'myapp',
      script: './index.js',
      instances: 'max',
      exec_mode: 'cluster',
      watch: false,
      max_memory_restart: '512M',
      env: {
        NODE_ENV: 'development',
        PORT: 3000,
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 8080,
      },
    },
  ],
};

Key fields to understand:

  • instances: number of processes; max uses all CPU cores
  • exec_mode: cluster or fork (single process)
  • watch: set false in production — file watching restarts on any change, including log rotation artifacts
  • max_memory_restart: PM2 will restart a worker that exceeds this threshold, guarding against memory leaks
  • env_production: injected when you pass --env production at start

Start (or reload) using the ecosystem file with the production environment:

pm2 start ecosystem.config.js --env production

To apply config changes to already-running workers with zero downtime:

pm2 reload ecosystem.config.js --env production

reload cycles workers one at a time. Use restart only when a hard restart is acceptable, as it kills all workers simultaneously.

Configure Startup on Boot

PM2 integrates with systemd on modern distros. The startup subcommand generates and installs a systemd unit that re-launches PM2 (and all saved processes) after a reboot.

Generate the Startup Hook

pm2 startup

PM2 detects your init system and prints a sudo command you must run. It will look like:

sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u youruser --hp /home/youruser

Copy and run that exact command — do not paraphrase it, as the paths are specific to your environment.

Save the Process List

After your apps are running as you want them, save the current process list so PM2 restores it on reboot:

pm2 save

This writes a dump file to ~/.pm2/dump.pm2. Any time you add or remove apps intended to survive reboots, run pm2 save again.

Verify the systemd Unit

systemctl status pm2-youruser.service

The unit should be active (running). If it is inactive or failed, check the journal:

journalctl -u pm2-youruser.service -n 50 --no-pager

Managing Logs

PM2 writes stdout and stderr to rotating log files under ~/.pm2/logs/ by default. Each app gets two files: appname-out.log and appname-error.log.

Tail Logs in Real Time

# All apps combined
pm2 logs

# One specific app
pm2 logs myapp

# Last 100 lines then follow
pm2 logs myapp --lines 100

Rotate Logs with pm2-logrotate

Without rotation, log files grow unbounded. Install the official PM2 log rotation module:

pm2 install pm2-logrotate

Then tune the defaults. These settings keep 30 rotated files, rotate when a file hits 10 MB, and check daily:

pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'

If you prefer to let the system's logrotate handle PM2 files instead, write a drop-in under /etc/logrotate.d/pm2 pointing at /home/youruser/.pm2/logs/*.log.

Essential Day-to-Day Commands

CommandWhat it does
pm2 listShow all managed processes and their status
pm2 monitReal-time CPU/memory dashboard in the terminal
pm2 stop myappStop without removing from process list
pm2 delete myappStop and remove from process list
pm2 describe myappFull metadata for a single process
pm2 env 0Show environment variables for process ID 0

Troubleshooting

App keeps restarting (errored or high restart count)

Run pm2 logs myapp --err --lines 50 to isolate the Node.js stack trace. Common causes: missing .env file, wrong NODE_ENV, or a port already in use. Check with ss -tlnp | grep 8080.

Changes to ecosystem.config.js are not picked up

A plain pm2 restart does not re-read the config file. You must run pm2 reload ecosystem.config.js or pm2 delete myapp && pm2 start ecosystem.config.js.

Process does not survive reboot despite running pm2 save

Confirm the systemd unit is enabled: systemctl is-enabled pm2-youruser.service. If it prints disabled, run pm2 startup again and re-run the generated command. Also check that pm2 save was run after the app was started, not before.

Cluster mode workers crash immediately

The most common cause is application code that calls process.on('message') or uses IPC in a way that conflicts with PM2's own cluster IPC. Test in fork mode first to isolate whether the issue is cluster-specific.

tested on:Ubuntu 24.04Debian 12Fedora 40Rocky 9

Frequently asked questions

What is the difference between pm2 restart and pm2 reload?
restart kills all workers simultaneously and brings them back up, causing a brief outage. reload cycles workers one at a time so there is always at least one process accepting connections — use reload in production cluster mode.
Should I run PM2 as root?
No. Run PM2 as the application user. The only time root is needed is to execute the one-time sudo command generated by pm2 startup, which installs the systemd unit file.
Can PM2 manage non-Node.js processes?
Yes. PM2 can manage any executable using the --interpreter flag or by setting the interpreter field in the ecosystem file, making it usable for Python, Ruby, or shell scripts.
Does PM2 replace a reverse proxy like Nginx?
No. PM2 manages Node.js processes; Nginx or Caddy should still sit in front to handle TLS termination, static files, and routing. PM2 cluster mode and Nginx are complementary.
How do I update PM2 itself without losing running processes?
Run npm install -g pm2 to install the new version, then run pm2 update. The pm2 update command instructs the old daemon to hand off to the new binary without restarting your applications.

Related guides