PM2 for Node.js: Production Process Management Guide
A fresh node server.js dies the moment you press Ctrl+C. Production needs a process manager that keeps your app running, restarts it when it crashes, spawns multiple workers for multi-core machines, handles logs, and survives server reboots. PM2 is the de-facto standard. This article walks through installing PM2, setting up an ecosystem file, running in cluster mode, log rotation, and the handful of gotchas that catch most teams.
Prerequisites
- A VPS (shared cPanel hosting does not let you run long-lived processes — PM2 is a VPS-or-above tool). Our VPS hosting plans include root SSH and support PM2.
- Node.js installed. Run
node -v; anything 18.x or above is fine. - Your app runnable from the command line (
node index.jsornpm start).
Install PM2
npm install -g pm2Global install puts pm2 on the PATH for every user. On a VPS, you typically install it as root once; each app user then uses it for their own app.
Verify:
pm2 --versionYour first PM2 start
From your app directory:
pm2 start server.js --name my-appOr for npm scripts:
pm2 start npm --name my-app -- startInspect the running process list:
pm2 listYou will see a table with app name, status (online / stopped / errored), CPU / memory usage, and restart count.
Other day-one commands:
pm2 logs my-app # tail logs
pm2 restart my-app # restart
pm2 stop my-app # stop but keep the entry
pm2 delete my-app # remove from PM2's listUse an ecosystem file (the right way)
Everything you did on the command line should be in a version-controlled config. Create ecosystem.config.js in your project root:
module.exports = {
apps: [
{
name: 'my-app',
script: './server.js',
instances: 2,
exec_mode: 'cluster',
watch: false,
max_memory_restart: '500M',
env: {
NODE_ENV: 'development',
},
env_production: {
NODE_ENV: 'production',
},
error_file: './logs/err.log',
out_file: './logs/out.log',
time: true,
},
],
};Start with:
pm2 start ecosystem.config.js --env productionNow your team can reproduce the exact run config by reading one file. Commit it to git.
Cluster mode — use all your CPU cores
A single Node process uses one CPU core. On a 4-core VPS, running 4 workers gives you 4× the throughput. PM2 does this in a single config change:
{
name: 'my-app',
script: './server.js',
instances: 'max', // use all cores, or set a number like 4
exec_mode: 'cluster',
}Zero-downtime reload (old workers drain, new workers start):
pm2 reload my-appThis is different from pm2 restart — reload drains; restart kills.
When cluster mode does NOT work:
- WebSocket apps without sticky sessions (different workers get different clients; state is split across workers). Use
instances: 1or add a session store like Redis. - In-memory caches (each worker has its own cache; invalidation is hard).
- Scheduled jobs that must run exactly once (cluster mode would run the job N times). Use a queue or a flag.
Log management
By default, PM2 writes logs to ~/.pm2/logs/<app>-out.log and <app>-error.log. Tail them:
pm2 logs my-app # both stdout and stderr
pm2 logs my-app --err # errors only
pm2 logs my-app --lines 200 # last 200 linesInstall the log rotation module so logs do not fill your disk:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 10
pm2 set pm2-logrotate:compress trueThis rotates each log at 10 MB, keeps the last 10, and gzips the older ones.
Survive server reboots
By default, PM2 processes disappear when the VPS reboots. Tell PM2 to register itself with systemd:
pm2 startup systemdThis prints a command that starts with sudo env PATH=... — copy and run it as root. Done once, persists forever.
Then save your current process list so PM2 restores it on boot:
pm2 saveTest it: sudo reboot, wait, SSH back in, run pm2 list — your app is already running.
Verify the systemd service:
sudo systemctl status pm2-youruserMonitoring
Built-in TUI:
pm2 monitShows live CPU, memory, logs per process. Fine for quick debugging.
For production observability, forward your logs to a central tool (Datadog, Loggly, or a self-hosted Grafana + Loki stack). pm2-logrotate does not do central aggregation — it only rotates local files.
Memory guard:
max_memory_restart: '500M',If the worker exceeds 500 MB RSS, PM2 restarts it. Useful defence against memory leaks while you find the root cause.
Common pitfalls
"Port already in use"
Something is already listening on your port. Could be:
- A zombie Node process —
pm2 listandpm2 delete <old-app-name> - Another system process —
sudo lsof -i :3000to find it - A previous failed start still holding the port briefly — wait 30 seconds, retry
PM2 processes disappear after reboot
You forgot pm2 save after pm2 startup. Do them in that order: startup first to register the systemd service, then save after your apps are running.
Logs fill the disk
You skipped pm2-logrotate. Install it immediately — unrotated PM2 logs can grow to gigabytes.
Cluster mode breaks WebSockets
Sticky sessions are required in cluster mode for WebSocket apps. Use @socket.io/sticky or deploy behind an nginx ip_hash load balancer. Simpler: use instances: 1 for WebSocket-heavy apps.
pm2 reload fails with "Could not find script"
Cluster mode needs to fork the process. If your script path is relative, PM2 can lose track of the working directory. Use absolute paths in ecosystem.config.js:
script: '/home/deploy/my-app/server.js',
cwd: '/home/deploy/my-app',Alternatives and when to pick them
| Tool | When to use |
|---|---|
| systemd | Single Node app, no cluster mode needed, you prefer native Linux. More typing, zero deps. |
| Supervisord | Multi-language app (Python + Node + shell workers all on one VPS). See our Supervisord guide. |
| Docker Compose | You already use Docker and want one tool for all processes. |
| Kubernetes | You have 10+ VPS nodes. Otherwise overkill. |
| PM2 | Single-VPS Node shop. Best ergonomics, mature, widely known. |
Frequently asked questions
Does PM2 work on shared hosting?
No. Shared hosting does not allow long-lived processes. You need a VPS.
Can I run multiple different Node apps on one VPS with PM2?
Yes. Each app gets its own entry in ecosystem.config.js (or you run pm2 start multiple times). They share PM2's management but run independently.
What is `exec_mode: fork` vs `cluster`?
fork — one process, one worker. Simple. cluster — PM2 uses Node's cluster module to spawn N workers sharing a port. Use cluster to utilise multiple CPU cores.
How do I restart PM2 on code deploy?
pm2 reload my-app (zero-downtime in cluster mode). For single-worker apps, use pm2 restart my-app — there will be a brief unavailability window, usually under a second.
Why is my app using 100% CPU?
Run pm2 monit to see which worker. Then pm2 logs <app> — look for infinite loops, runaway recursion, or a stuck request. node --inspect if you need to attach a debugger.
Can I limit PM2 to use less memory?
Yes. Set max_memory_restart per app. For system-wide limits, use cgroups via systemd's MemoryLimit on the pm2-youruser.service unit.
Is there a paid version?
PM2 Plus (keymetrics.io) — hosted monitoring, alerting, remote-control. Optional; the OSS version is fully featured for most shops.
Questions or stuck? [email protected] — we help VPS customers with PM2 setup as part of standard support.