
How to Deploy and Manage Node.js Apps in Production Using PM2
Spawning a Node.js process using raw commands like node server.js is fine for local development. However, running your production server this way is highly dangerous. If an unhandled exception triggers a crash, or if the server hosts run out of memory, the Node.js process will exit, taking your website offline.
To keep Node.js applications alive, handle crashes, utilize multi-core server processors, and configure log rotations, you need a Process Manager. The industry standard for Node.js is PM2.
In this guide, we will explore PM2, configure a production-grade ecosystem.config.js setup, enable multi-core Cluster Mode, and configure zero-downtime deployments.
Why You Need PM2
PM2 acts as a daemon process manager. Once installed, it runs in the background and supervises your Node.js processes:
- Automatic Restarts: If your application crashes due to an error, PM2 intercepts the crash and spins up a new instance in milliseconds.
- CPU Core Utilization (Cluster Mode): By default, Node.js runs on a single CPU core. PM2 can duplicate your application across all available CPU cores without code changes.
- Graceful Reloads: Deploy updates without dropping active user connections (zero-downtime).
- System Startup Persistence: Automatically restarts your Node.js applications if the host virtual machine reboots.
Configuring PM2 with ecosystem.config.js
While you can run PM2 using CLI flags, the best practice is declaring configurations in a structured file named ecosystem.config.js in your repository root.
module.exports = {
apps: [
{
name: 'my-node-app',
script: './dist/server.js',
// Cluster mode setup
instances: 'max', // Spawns one instance per CPU core
exec_mode: 'cluster', // Enables clustering
// Auto-restart configuration
watch: false, // Turn off in production
max_memory_restart: '1G', // Restart if RAM usage exceeds 1GB
autorestart: true,
// Log management paths
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Environment variables
env_production: {
NODE_ENV: 'production',
PORT: 3000,
},
},
],
};Running PM2: Essential Commands
Once your config file is written, deploy and manage your processes using these CLI commands:
# Start your application in production mode
pm2 start ecosystem.config.js --env production
# Check status of running instances
pm2 list
# Monitor real-time CPU, memory, and logs
pm2 monit
# Save the process list to revive on system reboot
pm2 saveZero-Downtime: Restart vs. Reload
When you update your code and pull changes to production:
- Running
pm2 restartkills all running instances instantly and starts them back up. During this transition, users visiting your site will see connection refused errors. - Running
pm2 reloadperforms a graceful reload. It restarts instances sequentially. PM2 keeps older instances alive to serve active HTTP requests until the new instances have finished booting up and are ready to take over, achieving zero-downtime.
# Apply code updates gracefully with zero downtime
pm2 reload ecosystem.config.jsLog Maintenance: PM2 Logrotate
If your application logs heavily, PM2’s out files can grow to gigabytes, filling up your server's SSD.
To prevent this, install the PM2-logrotate plugin. It automatically splits, compresses, and purges older logs:
pm2 install pm2-logrotateConfigure log limits:
# Force log rotation when log size hits 10MB
pm2 set pm2-logrotate:max_size 10M
# Keep a maximum of 30 historical log files
pm2 set pm2-logrotate:retain 30Conclusion
Deploying Node.js applications with PM2 provides enterprise-grade resilience. By leveraging Cluster Mode to parallelize workloads across all CPU cores, utilizing PM2 Reload to perform zero-downtime code updates, and setting up PM2 Logrotate to protect disk space, you can run high-availability Node.js services.