S Simplewala
Node.js DevOps

Zero-downtime Node.js deployments with PM2 on a VPS

PM2 cluster mode, rolling restarts, and a simple deploy script. Ship updates without dropping a single request.

Simplewala Team

Deploying a Node.js app by SSHing in, killing the process, and restarting it will drop every active connection. For a low-traffic hobby project that's fine. For anything real, you need zero-downtime restarts.

PM2 makes this simple with cluster mode and reload. Here's exactly how to set it up.

Why cluster mode?

Node.js is single-threaded. On a multi-core server, a single Node process leaves CPU cores idle. PM2's cluster mode forks your app across all available cores and load-balances incoming connections between them.

Cluster mode also enables zero-downtime restarts: PM2 reloads workers one at a time, keeping at least one worker alive throughout the process.

Step 1: Install PM2

npm install -g pm2

Or use Simplewala's Node.js installer, which includes PM2 automatically.

Step 2: Start your app in cluster mode

pm2 start npm --name "my-app" -i max -- start

-i max forks one worker per CPU core. You can also specify a number: -i 4.

Save the process list so PM2 restarts your app after a server reboot:

pm2 save
pm2 startup

Step 3: Zero-downtime reload

Use reload instead of restart when deploying updates:

pm2 reload my-app

PM2 sends SIGINT to one worker at a time and waits for it to finish handling in-flight requests before starting a new worker. Active connections are never dropped.

A simple deploy script

Create /srv/app/deploy.sh:

#!/bin/bash
set -e

cd /srv/app
git pull origin main
npm ci --production
npm run build
pm2 reload my-app
echo "Deploy complete"
chmod +x /srv/app/deploy.sh

Run it from your CI/CD pipeline or a GitHub Actions workflow:

- name: Deploy
  run: ssh root@$SERVER_IP '/srv/app/deploy.sh'

Environment variables

Never hardcode secrets in your source code. Create a .env file on the server and reference it in your PM2 ecosystem config:

// ecosystem.config.cjs
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'npm',
    args: 'start',
    instances: 'max',
    exec_mode: 'cluster',
    env_file: '/srv/app/.env',
  }]
};
pm2 start ecosystem.config.cjs

Monitoring

PM2 includes a built-in monitor:

pm2 monit

On Simplewala, PM2 logs are also visible in the portal under Server → Applications without needing SSH.

Summary

  • Use -i max to fork across all CPU cores
  • Use pm2 reload (not restart) for zero-downtime deploys
  • Persist your process list with pm2 save + pm2 startup
  • Store secrets in .env and reference them via env_file

Ready to simplify your hosting?

Deploy your first server in 90 seconds. All features included.

Start free