PM2 Cluster Mode: Setup, Configuration, and Production Deployment
Quick Answer
- What it does: PM2 Cluster Mode runs multiple instances of your Node.js application across all available CPU cores, providing load balancing and high availability for network applications (HTTP/HTTPS/TCP/UDP).
- Minimal command:
pm2 start app.js -i max— this starts your app in cluster mode, automatically creating one worker per CPU core. - Key requirement: Your application must be stateless (no in-memory session data, no local file writes from multiple workers) for cluster mode to work correctly.
- Zero-downtime reload: Use
pm2 reload <app_name>instead ofpm2 restartto restart workers one by one without dropping connections. - Version boundary: Works with Node.js 0.12+ and PM2 1.0+. The
-iflag is required to enable cluster mode; without it, PM2 defaults to fork mode.
What Problem It Solves
Node.js runs on a single thread by default, meaning it cannot utilize multiple CPU cores on a single machine. For production network applications (REST APIs, microservices, WebSocket servers), this limits throughput and creates a single point of failure.
PM2 Cluster Mode solves this by using Node.js's built-in cluster module to spawn multiple worker processes that share the same server port. The master process distributes incoming connections across workers using a round-robin algorithm, providing:
- CPU utilization: All cores are used, increasing request handling capacity
- High availability: If one worker crashes, the master spawns a replacement
- Zero-downtime deployments: Workers restart sequentially during
pm2 reload
Installation and Quick Start
Install PM2 globally:
BASHnpm install -g pm2
Start your application in cluster mode:
BASHpm2 start app.js -i max
This single command:
- Enables cluster mode (the
-iflag is required) - Creates one worker per CPU core (
max) - Names the process after the script filename
- Daemonizes the process (runs in background)
To verify it's working:
BASHpm2 list pm2 monit
Parameters and Environment Variables
The -i (instances) Parameter
The -i flag is required to enable cluster mode. Without it, PM2 runs in fork mode (single process).
| Value | Behavior |
|---|---|
max | Creates one worker per CPU core |
0 | Same as max |
-1 | Creates (CPU cores - 1) workers |
3 | Creates exactly 3 workers |
2 | Creates exactly 2 workers |
Example with a specific number:
BASHpm2 start app.js -i 4 --name my-api
Configuration File (ecosystem.config.js)
For production, use a configuration file instead of CLI flags:
JAVASCRIPTmodule.exports = { apps: [{ name: 'my-app', script: 'app.js', instances: 'max', exec_mode: 'cluster', env: { NODE_ENV: 'production', PORT: 3000 }, env_development: { NODE_ENV: 'development', PORT: 3001 } }] };
Start with the config file:
BASHpm2 start ecosystem.config.js
Switch environments:
BASHpm2 start ecosystem.config.js --env production
Root Cause Analysis: Why Cluster Mode Fails
Statelessness Requirement
PM2 Cluster Mode distributes requests across workers using round-robin. If your application stores session data in memory, a user's request may hit a different worker on the next request, losing the session.
Symptoms: Users are randomly logged out, shopping carts disappear, form data is lost.
Fix: Use an external session store (Redis, Memcached, database) or make the application stateless.
File System Conflicts
Multiple workers writing to the same file (logs, SQLite databases, temporary files) causes data corruption.
Symptoms: Corrupted log files, SQLITE_BUSY errors, missing data.
Fix:
- Use a logging library that supports concurrent writes (e.g., Winston with file rotation)
- Replace SQLite with PostgreSQL or MySQL
- Use Redis for caching instead of local files
Port Binding Issues
Cluster mode workers share the parent process's port automatically. However, if your application explicitly binds to a port in the worker code, you may see EADDRINUSE errors.
Fix: Only call server.listen() once in the master process, or let PM2 handle port sharing automatically.
Common Errors and Fixes
| Error | Cause | Solution |
|---|---|---|
Error: listen EADDRINUSE: address already in use :::3000 | Port already occupied | lsof -i :3000 to find the process, then kill it or change the port |
Error: Cannot find module 'app.js' | Wrong script path | Use absolute path or run PM2 from the project root directory |
Error: Process exited with code 1 | Application startup failure | Check pm2 logs for detailed error (missing dependencies, syntax errors, missing env vars) |
pm2: command not found | PM2 not installed or not in PATH | Run npm install -g pm2 or use npx pm2 |
Production Notes and Security Checks
Essential Production Setup
BASH# Save the process list for automatic recovery pm2 save # Generate startup script (systemd, init.d, etc.) pm2 startup # Monitor logs pm2 logs # Monitor metrics pm2 monit
Security and Resource Limits
-
File permissions: PM2 runs as the current user. Ensure log directories, PID files, and application directories have correct permissions.
-
File descriptor limits: Cluster mode multiplies open file handles. Increase the system limit:
BASHulimit -n 65536 -
Firewall: PM2 does not provide network isolation. Always put a reverse proxy (Nginx, HAProxy) in front of PM2-managed applications.
-
Graceful shutdown: Your application should listen for
SIGINTto clean up connections:JAVASCRIPTprocess.on('SIGINT', () => { server.close(() => process.exit(0)); });
Zero-Downtime Deployment
BASH# Instead of restart (kills all workers at once) pm2 reload my-app # Force reload if graceful shutdown fails pm2 reload my-app --kill-timeout 3000
The reload command restarts workers one by one, ensuring at least one worker is always serving requests.
Comparison With Alternatives
| Feature | PM2 Cluster Mode | Nginx + PM2 Fork | Docker Swarm / Kubernetes |
|---|---|---|---|
| Load balancing | Round-robin (built-in) | Multiple algorithms (least connections, IP hash, etc.) | Service mesh / ingress |
| Zero-downtime | pm2 reload | Requires Nginx reload | Rolling updates |
| Process management | Node.js-focused | Requires separate Nginx config | Full container orchestration |
| Learning curve | Low | Medium | High |
| Resource overhead | Minimal | Moderate (Nginx process) | High (control plane) |
| Stateful app support | No (must be stateless) | Yes (sticky sessions via IP hash) | Yes (with persistent volumes) |
When to use PM2 Cluster Mode: Small to medium Node.js applications on a single server, where simplicity and low overhead matter more than advanced routing features.
When to use alternatives: Multi-server deployments, applications requiring sticky sessions, or when you need advanced load-balancing algorithms.
FAQ
Q: What is the difference between PM2 Cluster Mode and PM2 Fork Mode?
A: Fork Mode is the default. Each instance runs in a separate process with its own port, suitable for non-network applications (cron jobs, scripts). Cluster Mode uses Node.js's cluster module so workers share the same port, provides built-in load balancing, and is designed for network applications. Cluster Mode requires stateless applications; Fork Mode has no such restriction.
Q: How do I achieve zero-downtime deployment with PM2 Cluster Mode?
A: Use pm2 reload <app_name>. PM2 restarts workers one by one, ensuring at least one worker is always serving. Your application should listen for SIGINT to perform graceful shutdown (close database connections, finish current requests). If the app doesn't close within the timeout, PM2 force-kills it.
Q: How do I manage environment variables in cluster mode?
A: Set them in the ecosystem.config.js file under the env field. All workers inherit the same environment variables. Example:
JAVASCRIPT{ apps: [{ script: 'app.js', instances: 'max', exec_mode: 'cluster', env: { NODE_ENV: 'production', PORT: 3000 } }] }
You can also use pm2 start app.js --env production to switch environments.