
- PM2
- Node.js
- Deployment
- Process Management
- VPS
PM2 Node.js Process Management Guide
A complete guide to PM2 for Node.js applications — starting, stopping, monitoring, clustering, log management, ecosystem config files, and surviving server reboots.
PM2 is the standard process manager for Node.js applications in production. It keeps your app running after crashes, restarts it on server reboots, provides built-in log management, and supports cluster mode for multi-core performance. This guide covers everything you need for a production setup.
Installation
Install PM2 globally with npm:
sudo npm install -g pm2
Verify the installation:
pm2 --version
Starting Applications
Start a script directly
pm2 start app.js --name "my-app"
Start an npm script
pm2 start npm --name "my-app" -- start
Start a specific entry point
For Astro (Node adapter), Next.js standalone, or any custom server file:
# Astro (Node adapter)
pm2 start dist/server/entry.mjs --name "astro-app"
# Next.js standalone
pm2 start .next/standalone/server.js --name "next-app"
# Custom Express server
pm2 start server.js --name "api-server"
For a complete Astro + Nginx + PM2 setup, see Deploying Astro on a VPS with Nginx. For Next.js deployments, see Deploying Next.js with Nginx or Deploying Next.js with Apache2.
Pass environment variables at start
pm2 start app.js --name "my-app" --env production
# or explicitly:
PORT=8080 NODE_ENV=production pm2 start app.js --name "my-app"
Core Process Commands
pm2 list # List all running processes
pm2 status # Same as pm2 list
pm2 show my-app # Detailed info for one process
pm2 stop my-app # Stop (keeps in list)
pm2 start my-app # Start a stopped process
pm2 restart my-app # Restart (brief downtime)
pm2 reload my-app # Zero-downtime restart (cluster mode)
pm2 delete my-app # Remove from list entirely
pm2 stop all # Stop all processes
pm2 restart all # Restart all processes
pm2 delete all # Remove all processes
Processes can be referenced by name or by their numeric ID shown in pm2 list.
Surviving Server Reboots
This is the most important step for production. Without it, your app won’t restart after a reboot.
1. Generate a startup script
pm2 startup
PM2 prints a command tailored to your system. Copy and run it — it looks like:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
2. Save the current process list
pm2 save
This saves the list of running processes to ~/.pm2/dump.pm2. On reboot, PM2 restores them automatically.
Run pm2 save again whenever you add, remove, or change a process.
3. Verify startup is registered
pm2 ls # confirm processes are listed
sudo systemctl status pm2-$(whoami)
Ecosystem Configuration File
For anything beyond a simple one-liner, use an ecosystem file. It keeps all your PM2 configuration in version control.
Create ecosystem.config.cjs in your project root:
// ecosystem.config.cjs
module.exports = {
apps: [
{
name: 'my-app',
script: 'dist/server/entry.mjs',
// Number of instances — 'max' uses all CPU cores
instances: 1,
// Restart automatically on crash
autorestart: true,
// Watch files and restart on changes (use in dev only)
watch: false,
// Memory limit — restart if exceeded
max_memory_restart: '512M',
// Environment variables per mode
env: {
NODE_ENV: 'development',
PORT: 4321,
},
env_production: {
NODE_ENV: 'production',
PORT: 4321,
},
},
],
};
Start with the ecosystem file:
# Development environment
pm2 start ecosystem.config.cjs
# Production environment
pm2 start ecosystem.config.cjs --env production
Other commands work the same way:
pm2 restart ecosystem.config.cjs --env production
pm2 reload ecosystem.config.cjs --env production # zero-downtime
pm2 stop ecosystem.config.cjs
pm2 delete ecosystem.config.cjs
Cluster Mode
Cluster mode spawns one process per CPU core and load-balances incoming connections across them. This is the fastest way to use all cores on a multi-core VPS without changing your app code.
// ecosystem.config.cjs
module.exports = {
apps: [
{
name: 'my-app',
script: 'server.js',
instances: 'max', // one per CPU core
exec_mode: 'cluster', // required for load balancing
autorestart: true,
env_production: {
NODE_ENV: 'production',
PORT: 3000,
},
},
],
};
In cluster mode, use pm2 reload instead of pm2 restart to achieve zero-downtime updates — PM2 cycles workers one at a time.
Caution: Cluster mode requires your app to be stateless. In-memory session storage, WebSocket connections, and anything stored in a global variable will not be shared across workers. Use Redis or a database for shared state.
Log Management
View logs
pm2 logs # Stream all logs
pm2 logs my-app # Stream logs for one app
pm2 logs my-app --lines 100 # Show last 100 lines
Log file locations
Logs are stored in ~/.pm2/logs/:
~/.pm2/logs/my-app-out.log # stdout
~/.pm2/logs/my-app-error.log # stderr
Flush logs
pm2 flush # Delete all log files
pm2 flush my-app # Delete logs for one app
Log rotation
Install the PM2 log rotation module to avoid logs filling up the disk:
pm2 install pm2-logrotate
Configure it:
pm2 set pm2-logrotate:max_size 50M # rotate when file exceeds 50 MB
pm2 set pm2-logrotate:retain 14 # keep 14 rotated files
pm2 set pm2-logrotate:compress true # gzip rotated files
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-mm-ss
Monitoring
Built-in terminal dashboard
pm2 monit
Shows CPU and memory usage per process in real time.
Process metrics
pm2 show my-app
Displays uptime, restart count, memory, CPU, log paths, and more.
Web dashboard (PM2 Plus)
PM2 offers a hosted web dashboard at app.pm2.io. Free tier available. Connect with:
pm2 link <secret_key> <public_key>
Deployment Workflow
A typical deployment after a code update:
# 1. Pull latest code on server
git pull
# 2. Install any new dependencies
npm install --omit=dev
# 3. Rebuild (if applicable)
npm run build
# 4. Reload the process (zero-downtime in cluster mode, brief restart otherwise)
pm2 reload my-app
# 5. Save the process list if anything changed
pm2 save
Watch Mode (Development Only)
PM2 can watch files and restart the process automatically on changes. Never use this in production — it restarts on every file modification and causes excessive CPU usage.
pm2 start app.js --name "dev-app" --watch
pm2 start app.js --name "dev-app" --watch --ignore-watch="node_modules logs"
Important Notes
- Always run
pm2 saveafter adding or changing processes, so the state persists across reboots. - In cluster mode, use
pm2 reloadnotpm2 restartto achieve zero-downtime updates. - Avoid
--watchin production — it is for development only. - Store your
ecosystem.config.cjsin version control so your PM2 setup is reproducible. - Use
pm2-logrotateon any long-running server to prevent logs from filling your disk.
Frequently Asked Questions
What’s the difference between pm2 restart and pm2 reload?
restart kills the process and starts a new one — there is a brief moment of downtime. reload (cluster mode only) replaces workers one at a time while the others continue handling requests, achieving zero downtime.
My app isn’t restarting after a server reboot. What’s wrong?
You likely skipped one of the two steps: running the pm2 startup command (including the sudo env ... command it prints) and running pm2 save. Both are required.
How do I run multiple apps on the same server?
List them all in the apps array of your ecosystem file, or start each one separately with a unique --name. Give each app a different port and create a separate Nginx server block for each domain.
How do I set environment variables securely?
Don’t store secrets in ecosystem.config.cjs if it’s in version control. Instead, set them in a .env file on the server and load them at startup, or export them in the shell before running PM2. Alternatively use the env_production block in the ecosystem file for non-sensitive config only.
Can PM2 manage non-Node.js processes?
Yes — PM2 can manage any executable. Use interpreter: 'python3' or interpreter: 'none' in the ecosystem file. However, PM2 was designed for Node.js and its language-specific features (cluster mode, --harmony flags, etc.) only apply to Node.js processes.
How do I completely uninstall PM2?
pm2 delete all
pm2 unstartup
sudo npm uninstall -g pm2
rm -rf ~/.pm2