PM2 Complete Guide 2026: Node.js Process Manager for Production

Sanjeev SharmaSanjeev Sharma
4 min read

Advertisement

PM2 2026: Keep Node.js Running Forever

PM2 is the production process manager for Node.js. It handles crashes, restarts, clustering, monitoring, and log rotation — all in one tool.

Installation and Basic Usage

npm install -g pm2

# Start an app
pm2 start app.js
pm2 start dist/server.js --name "api"
pm2 start "npm run start" --name "nextjs"

# Cluster mode (use all CPU cores)
pm2 start app.js -i max     # Max instances = CPU count
pm2 start app.js -i 4       # Exactly 4 instances

# Check status
pm2 status
pm2 list

# Monitoring
pm2 monit  # Real-time CPU/Memory dashboard

# Logs
pm2 logs           # All logs
pm2 logs api       # App-specific logs
pm2 logs --lines 200  # Last 200 lines

Ecosystem Configuration

// ecosystem.config.js
module.exports = {
  apps: [
    {
      name: 'webcoderspeed-api',
      script: 'dist/server.js',

      // Cluster mode
      instances: 'max',      // or specific number
      exec_mode: 'cluster',

      // Environment
      env: {
        NODE_ENV: 'development',
        PORT: 3000,
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 3000,
      },

      // Restart behavior
      max_restarts: 10,
      restart_delay: 4000,      // Wait 4s before restart
      exp_backoff_restart_delay: 100,  // Exponential backoff

      // Memory monitoring
      max_memory_restart: '1G',  // Restart if over 1GB

      // Watch files (development only)
      watch: false,             // Set true for dev

      // Logs
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      out_file: './logs/out.log',
      error_file: './logs/error.log',
      log_file: './logs/combined.log',
      merge_logs: true,

      // Health monitoring
      health_check_grace_period: 3000,
      listen_timeout: 10000,
      kill_timeout: 5000,

      // Graceful restart
      wait_ready: true,       // Wait for app to signal ready
      graceful_timeout: 10000,
    },

    // Background worker
    {
      name: 'email-worker',
      script: 'dist/workers/email.js',
      instances: 2,
      exec_mode: 'cluster',
      cron_restart: '0 4 * * *',  // Restart daily at 4 AM
    },
  ],
}

Zero-Downtime Deploys

# Reload (graceful) — maintains cluster availability
pm2 reload webcoderspeed-api

# Or use ecosystem config
pm2 reload ecosystem.config.js --env production

# Graceful shutdown signal in Node.js
process.on('SIGINT', async () => {
  console.log('Graceful shutdown initiated...')

  // Close server, finish pending requests
  server.close(async () => {
    await db.disconnect()
    await redis.disconnect()
    console.log('Server closed')
    process.exit(0)
  })
})

// Signal PM2 that app is ready
process.send('ready')

Deploy Workflow

# Deploy with PM2 deploy
# ecosystem.config.js — deploy section
module.exports = {
  apps: [...],
  deploy: {
    production: {
      user: 'ubuntu',
      host: ['webcoderspeed.com'],
      ref: 'origin/main',
      repo: 'git@github.com:webcoderspeed/app.git',
      path: '/app',
      'pre-deploy-local': '',
      'post-deploy': 'npm ci && npm run build && pm2 reload ecosystem.config.js --env production',
    }
  }
}

# Setup
pm2 deploy production setup

# Deploy
pm2 deploy production

Startup Scripts (Survive Server Reboots)

# Generate startup script for your OS
pm2 startup

# Output: sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu

# Run the command it outputs, then:
pm2 save  # Save current process list

# Now PM2 starts on boot automatically

# Verify
sudo systemctl status pm2-ubuntu

Monitoring and Metrics

# Web dashboard (PM2 Plus)
pm2 link <secret> <public>  # Connect to PM2 Plus

# Local monitoring API
pm2 describe api   # Detailed info
pm2 env 0         # App 0 environment variables

# Programmatic monitoring
const pm2 = require('pm2')

pm2.connect(() => {
  pm2.list((err, processDescriptionList) => {
    processDescriptionList.forEach(proc => {
      console.log({
        name: proc.name,
        pid: proc.pid,
        cpu: proc.monit.cpu,
        memory: proc.monit.memory / 1024 / 1024 + 'MB',
        uptime: proc.pm2_env.pm_uptime,
        restarts: proc.pm2_env.restart_time,
      })
    })
    pm2.disconnect()
  })
})

Log Management

# Install log rotation
pm2 install pm2-logrotate

# Configure
pm2 set pm2-logrotate:max_size 10M    # Rotate at 10MB
pm2 set pm2-logrotate:retain 7        # Keep 7 days
pm2 set pm2-logrotate:compress true   # Gzip old logs

# Flush logs
pm2 flush

# Ship logs to external service
# stdout goes to: /var/log/pm2/app-out.log
# Use filebeat, fluentd, or Datadog agent to ship to ELK

Cluster Mode Tips

// cluster.js — Share state between cluster workers
const cluster = require('cluster')

if (cluster.isMaster) {
  // Master process: coordinate
  for (let i = 0; i < require('os').cpus().length; i++) {
    cluster.fork()
  }
} else {
  // Worker: start your server
  require('./server.js')
}

// With PM2 cluster mode, you don't need this code —
// PM2 handles clustering automatically

// But you DO need to handle shared state:
// - Use Redis for sessions (not memory)
// - Use Redis for caching (not in-process)
// - Use message queues for background jobs
// - Use distributed locks for cron jobs

PM2 is the simplest production setup for Node.js. It's battle-tested, has excellent documentation, and handles 99% of process management needs without Kubernetes complexity.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro