PM2 Complete Guide 2026: Node.js Process Manager for Production
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
- Ecosystem Configuration
- Zero-Downtime Deploys
- Deploy Workflow
- Startup Scripts (Survive Server Reboots)
- Monitoring and Metrics
- Log Management
- Cluster Mode Tips
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