Tutorials

PM2 for Node.js - Complete Guide

February 17, 202614 min readBy Manas

PM2 is the most popular process manager for Node.js applications. It keeps your apps running, handles restarts, and provides powerful monitoring. This guide covers everything from basics to advanced usage.

What is PM2?

PM2 (Process Manager 2) is a production process manager for Node.js with:

  • Process management (start, stop, restart)
  • Auto-restart on crashes
  • Load balancing with cluster mode
  • Log management
  • Monitoring dashboard
  • Deployment system

Installation

Global Installation

bash
npm install -g pm2

Verify Installation

bash
pm2 --version

Basic Usage

Start an Application

bash
# Start a script
pm2 start app.js

# Start with a name
pm2 start app.js --name my-app

# Start npm script
pm2 start npm --name my-app -- start

Manage Processes

bash
pm2 list                 # List all processes
pm2 stop my-app          # Stop a process
pm2 restart my-app       # Restart a process
pm2 delete my-app        # Remove from PM2
pm2 stop all             # Stop all processes
pm2 restart all          # Restart all processes

View Logs

bash
pm2 logs                 # All logs
pm2 logs my-app          # Specific app logs
pm2 logs --lines 100     # Last 100 lines
pm2 flush                # Clear all logs

Ecosystem Configuration

For complex setups, use an ecosystem file.

Create ecosystem.config.js

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    instances: 2,
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    }
  }]
};

Start with Ecosystem

bash
pm2 start ecosystem.config.js
pm2 start ecosystem.config.js --env production

Cluster Mode

Cluster mode runs multiple instances for better performance.

Enable Clustering

bash
# Start with specific instances
pm2 start app.js -i 4

# Use all CPU cores
pm2 start app.js -i max

Ecosystem Cluster Config

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    instances: 'max',
    exec_mode: 'cluster',
    instance_var: 'INSTANCE_ID'
  }]
};

Scale Instances

bash
pm2 scale my-app 4       # Scale to 4 instances
pm2 scale my-app +2      # Add 2 instances
pm2 scale my-app -1      # Remove 1 instance

Auto-Restart Configuration

On System Reboot

bash
pm2 startup              # Generate startup script
pm2 save                 # Save current process list

On File Changes (Development)

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    watch: true,
    ignore_watch: ['node_modules', 'logs'],
    watch_options: {
      followSymlinks: false
    }
  }]
};

On Memory Limit

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    max_memory_restart: '500M'
  }]
};

Monitoring

Built-in Monitor

bash
pm2 monit

Shows real-time:

  • CPU usage
  • Memory usage
  • Loop delay
  • Request count

Process Information

bash
pm2 show my-app          # Detailed info
pm2 describe my-app      # Same as show

PM2 Plus (Web Dashboard)

bash
pm2 plus                 # Connect to PM2 Plus

Provides:

  • Web-based dashboard
  • Historical metrics
  • Alerting
  • Remote management

Log Management

Log Configuration

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    output: './logs/out.log',
    error: './logs/error.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    merge_logs: true
  }]
};

Log Rotation

Install pm2-logrotate:

bash
pm2 install pm2-logrotate

Configure:

bash
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true

Environment Variables

In Ecosystem File

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    env: {
      NODE_ENV: 'development',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 8080
    },
    env_staging: {
      NODE_ENV: 'staging',
      PORT: 3001
    }
  }]
};

Switch Environments

bash
pm2 start ecosystem.config.js --env production
pm2 restart my-app --env staging

Deployment

Deployment Configuration

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js'
  }],
  deploy: {
    production: {
      user: 'deploy',
      host: 'your_server_ip',
      ref: 'origin/main',
      repo: 'git@github.com:user/repo.git',
      path: '/var/www/my-app',
      'pre-deploy-local': '',
      'post-deploy': 'npm install && pm2 reload ecosystem.config.js --env production',
      'pre-setup': ''
    }
  }
};

Deploy Commands

bash
# Initial setup
pm2 deploy production setup

# Deploy
pm2 deploy production

# Rollback
pm2 deploy production revert 1

Graceful Shutdown

Handle shutdown signals properly:

In Your App

javascript
process.on('SIGINT', async () => {
  console.log('Shutting down gracefully...');
  
  // Close database connections
  await db.close();
  
  // Close server
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });
  
  // Force exit after timeout
  setTimeout(() => {
    process.exit(1);
  }, 10000);
});

PM2 Configuration

javascript
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    kill_timeout: 5000,
    wait_ready: true,
    listen_timeout: 10000
  }]
};

Common Patterns

Discord Bot

javascript
module.exports = {
  apps: [{
    name: 'discord-bot',
    script: 'bot.js',
    instances: 1,
    autorestart: true,
    max_memory_restart: '500M',
    env: {
      NODE_ENV: 'production',
      DISCORD_TOKEN: 'your_token'
    }
  }]
};

API Server with Clustering

javascript
module.exports = {
  apps: [{
    name: 'api-server',
    script: 'server.js',
    instances: 'max',
    exec_mode: 'cluster',
    max_memory_restart: '1G',
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
};

Multiple Apps

javascript
module.exports = {
  apps: [
    {
      name: 'api',
      script: 'api/server.js',
      instances: 4,
      exec_mode: 'cluster'
    },
    {
      name: 'worker',
      script: 'worker/index.js',
      instances: 2
    },
    {
      name: 'scheduler',
      script: 'scheduler/cron.js',
      instances: 1
    }
  ]
};

Troubleshooting

Process Keeps Restarting

Check logs for errors:

bash
pm2 logs my-app --err --lines 50

High Memory Usage

  • Check for memory leaks
  • Set max_memory_restart
  • Review your code for issues

Cluster Mode Issues

Not all apps work in cluster mode. Ensure:

  • No shared state between instances
  • Use Redis for sessions
  • Stateless design

Useful Commands Reference

bash
# Process management
pm2 start app.js
pm2 stop all
pm2 restart all
pm2 delete all

# Monitoring
pm2 list
pm2 monit
pm2 show app-name

# Logs
pm2 logs
pm2 flush

# System
pm2 startup
pm2 save
pm2 unstartup

# Updates
pm2 update

Conclusion

PM2 is essential for running Node.js in production. It handles crashes, provides monitoring, and enables zero-downtime deployments. Start with basic usage and gradually adopt advanced features as needed.

HeavenCloud hosting works perfectly with PM2, providing the reliable infrastructure your Node.js applications need.

Deploy on HeavenCloud

Discord bots, Lavalink nodes, and VPS, instant setup with NVMe and DDoS protection.