How to Use Pm2 for Nodejs
How to Use PM2 for Node.js Running a Node.js application in production is more than just typing node app.js . While this works perfectly for development, it’s not suitable for real-world deployment. Applications crash. Servers reboot. Processes die. Without proper process management, your service goes offline — and users vanish. That’s where PM2 comes in. PM2 is a production-grade process manager
How to Use PM2 for Node.js
Running a Node.js application in production is more than just typing node app.js. While this works perfectly for development, its not suitable for real-world deployment. Applications crash. Servers reboot. Processes die. Without proper process management, your service goes offline and users vanish. Thats where PM2 comes in.
PM2 is a production-grade process manager for Node.js applications. It ensures your apps stay online, restart automatically after crashes, scale across CPU cores, and provide detailed monitoring all with minimal configuration. Whether you're managing a single API endpoint or a cluster of microservices, PM2 is the industry-standard tool that keeps Node.js applications stable, scalable, and observable.
In this comprehensive guide, youll learn how to install, configure, monitor, and optimize Node.js applications using PM2. From basic startup commands to advanced clustering, logging, and deployment automation, this tutorial covers everything you need to run Node.js applications like a pro.
Step-by-Step Guide
1. Installing PM2
Before you can manage your Node.js applications, you need to install PM2 globally on your system. PM2 is distributed via npm (Node Package Manager), so ensure Node.js and npm are installed first.
To check your Node.js and npm versions, run:
node --version
npm --version
If either command returns an error, install Node.js from the official website: https://nodejs.org.
Once Node.js is confirmed, install PM2 globally using npm:
npm install -g pm2
After installation, verify PM2 is working by checking its version:
pm2 --version
You should see the current version number (e.g., 5.3.0 or higher). If youre on a system where global packages require elevated permissions (like Linux/macOS), you might need to use sudo:
sudo npm install -g pm2
For production environments, avoid using sudo if possible. Instead, configure npm to install global packages in a user-owned directory to prevent permission issues. Refer to the Best Practices section for details.
2. Starting a Node.js Application with PM2
Lets assume you have a simple Express.js application in a file named server.js:
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/', (req, res) => {
res.send('Hello from PM2!');
});
app.listen(PORT, () => {
console.log(Server running on http://localhost:${PORT});
});
To start this application with PM2, navigate to the directory containing server.js and run:
pm2 start server.js
PM2 will output a status table showing:
- Name: The application name (defaults to the filename)
- id: A unique process ID assigned by PM2
- mode: The execution mode (fork mode by default)
- pid: The system process ID
- status: online means the app is running
- cpu and mem: Real-time resource usage
- uptime: How long the app has been running
PM2 automatically starts the application in the background and keeps it running even if you close your terminal. This is the first major advantage over using node server.js.
3. Naming Your Applications
By default, PM2 assigns the filename as the application name. However, for clarity especially when managing multiple apps its best to assign a custom name:
pm2 start server.js --name "my-api-server"
Now, when you run pm2 list, youll see my-api-server instead of server.js. This improves readability and makes management easier.
4. Starting Applications with Configuration Files
For complex applications, hardcoding startup options in the terminal becomes unwieldy. PM2 supports configuration files in JSON, YAML, or JavaScript format. The most common is ecosystem.config.js.
Create a file named ecosystem.config.js in your project root:
module.exports = {
apps: [{
name: 'my-api-server',
script: './server.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_restarts: 10,
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production',
PORT: 8080
}
}]
};
Lets break down the key options:
- name: Human-readable name for the app
- script: Path to the main Node.js file
- instances: Number of instances to spawn. Use
'max'to spawn one per CPU core - exec_mode:
'cluster'enables clustering (recommended for production),'fork'runs a single instance - autorestart: Automatically restart if the process crashes
- watch: Monitor file changes and restart on modification (useful in development)
- max_restarts: Maximum number of restarts within a time window to prevent infinite loops
- error_file and out_file: Custom log file paths
- env and env_production: Environment-specific variables
Start your app using the configuration file:
pm2 start ecosystem.config.js
PM2 reads the configuration and starts the app with all specified settings. You can also start multiple apps from the same file by adding more objects to the apps array.
5. Managing Multiple Applications
Once you start managing multiple apps, youll need to know how to list, stop, restart, and delete them.
List all running apps:
pm2 list
Stop a specific app:
pm2 stop my-api-server
Restart a specific app:
pm2 restart my-api-server
Reload all apps (zero-downtime restart):
pm2 reload all
Delete an app from PM2s process list:
pm2 delete my-api-server
Delete all apps:
pm2 delete all
These commands are essential for routine maintenance. Always use reload instead of restart in production environments to avoid downtime especially when using clustering.
6. Enabling Clustering for Better Performance
Node.js is single-threaded. By default, PM2 runs your app in fork mode, meaning only one CPU core is utilized. On multi-core servers, this wastes available resources.
Clustering allows PM2 to spawn multiple instances of your app, distributing incoming requests across all CPU cores. This dramatically improves throughput and responsiveness.
Enable clustering by setting instances: 'max' and exec_mode: 'cluster' in your config file, as shown earlier. Then restart your app:
pm2 restart ecosystem.config.js
Run pm2 list again. Youll now see multiple instances one per CPU core. For example, on a 4-core server, youll see 4 instances of your app, each with its own PID.
PM2 automatically load-balances HTTP traffic across these instances using its built-in load balancer. No additional reverse proxy (like Nginx) is required for basic clustering though combining PM2 with Nginx is recommended for production-grade setups.
7. Monitoring Applications in Real-Time
PM2 includes a built-in real-time monitoring dashboard. To open it, run:
pm2 monit
This opens a terminal-based interface displaying:
- CPU and memory usage per process
- Number of HTTP requests (if using Express or similar frameworks)
- Restart count
- Uptime
- Network I/O
Press q to exit the monitor.
For a more visual experience, install PM2s web-based dashboard:
pm2 install pm2-logrotate
pm2 install pm2-web
Then start the web interface:
pm2 web
Open your browser and navigate to http://localhost:9615. Youll see a clean dashboard with charts, logs, and process controls. This is ideal for DevOps teams managing multiple servers.
8. Logging and Log Management
PM2 automatically captures stdout and stderr and stores them in log files. By default, logs are saved in ~/.pm2/logs/.
To view the latest logs for a specific app:
pm2 logs my-api-server
To follow logs in real-time (like tail -f):
pm2 logs my-api-server --raw
To clear logs:
pm2 flush
For production environments, configure log rotation to prevent disk space exhaustion. Install the pm2-logrotate module:
pm2 install pm2-logrotate
This module automatically rotates logs daily and keeps only the last 10 files. You can customize settings by editing:
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD-HH-mm-ss
These settings limit log files to 10MB, retain 30 rotated files, and compress old logs with gzip saving significant disk space over time.
9. Starting PM2 on System Boot (Auto-Startup)
When your server reboots, PM2 doesnt automatically restart your apps. To ensure your applications come back online after a power failure or system update, configure PM2 to start on boot.
Run the following command:
pm2 startup
PM2 will detect your system (systemd, init.d, etc.) and output a command to run with sudo. For example:
[PM2] You have to run this command as root. Execute the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
Copy and run that exact command. Then save your current process list:
pm2 save
This saves the current running apps to a JSON file (~/.pm2/dump.pm2) that PM2 loads on startup. Now, after a reboot, your apps will automatically restart no manual intervention needed.
10. Deploying Applications with PM2
PM2 includes a built-in deployment tool that simplifies pushing code to remote servers. This is especially useful for CI/CD workflows.
Create a deployment configuration in your ecosystem.config.js:
module.exports = {
apps: [{...}], // your app config
deploy: {
production: {
user: 'ubuntu',
host: 'your-server-ip',
ref: 'origin/main',
repo: 'git@github.com:yourusername/your-repo.git',
path: '/var/www/your-app',
'post-deploy': 'npm install && pm2 reload ecosystem.config.js --env production'
}
}
};
Before deploying, ensure:
- SSH key authentication is set up between your local machine and server
- Git is installed on the server
- Node.js and PM2 are installed on the server
Initialize the deployment environment on the server:
pm2 deploy ecosystem.config.js production setup
This creates the required directories and clones your repo.
To deploy new code:
pm2 deploy ecosystem.config.js production
PM2 will:
- Fetch the latest code from the specified Git branch
- Install dependencies with
npm install - Reload the app using the production environment
This ensures zero-downtime deployments and is ideal for automated pipelines.
Best Practices
1. Never Run PM2 as Root
Running Node.js applications as root is a serious security risk. If your app is compromised, an attacker gains full system access.
Create a dedicated non-root user for your application:
sudo adduser nodeapp
sudo usermod -aG sudo nodeapp
Switch to that user and install PM2 globally under their home directory:
su - nodeapp
npm install -g pm2
Then start your apps under this user. This limits potential damage if your application is exploited.
2. Use Environment Variables for Configuration
Never hardcode API keys, database passwords, or secrets in your source code. Use environment variables instead.
Define them in your ecosystem.config.js under env_production or load them from a .env file using dotenv:
const dotenv = require('dotenv');
dotenv.config();
module.exports = {
apps: [{
name: 'my-app',
script: './server.js',
env_production: {
NODE_ENV: 'production',
DB_HOST: process.env.DB_HOST,
DB_PASSWORD: process.env.DB_PASSWORD,
API_KEY: process.env.API_KEY
}
}]
};
Then create a .env.production file (never commit it to Git):
DB_HOST=localhost
DB_PASSWORD=supersecret123
API_KEY=abc123xyz
Load it before starting PM2:
source .env.production && pm2 start ecosystem.config.js --env production
3. Set Resource Limits
Prevent memory leaks or runaway processes from crashing your server. Use PM2s built-in memory limit:
max_memory_restart: '1G'
This restarts the app if it exceeds 1GB of memory. Combine this with proper monitoring to detect memory leaks early.
4. Use a Reverse Proxy (Nginx)
While PM2s clustering handles load balancing, its not designed to serve static files, handle SSL termination, or manage multiple domains. Use Nginx as a reverse proxy in front of PM2.
Install Nginx:
sudo apt install nginx
Create a site configuration:
sudo nano /etc/nginx/sites-available/myapp
Add:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Now your app is accessible via http://yourdomain.com, with SSL, caching, and security headers managed by Nginx.
5. Monitor Logs and Metrics Regularly
Set up centralized logging with tools like Loggly, Papertrail, or ELK stack. Forward PM2 logs to these services for long-term analysis and alerting.
Use PM2s pm2 logs --raw to pipe logs to external tools:
pm2 logs myapp --raw | logger -t pm2-app
Or use pm2-monit to send metrics to Prometheus or Grafana.
6. Regularly Update PM2 and Node.js
Security patches and performance improvements are released regularly. Keep PM2 updated:
npm install -g pm2@latest
Also, keep Node.js updated. LTS versions are recommended for production. Avoid using outdated or deprecated Node.js versions.
7. Use Process Naming Conventions
Use consistent naming: api-server, auth-service, notification-worker. This makes it easy to identify and manage services in large deployments.
Tools and Resources
Essential PM2 Modules
Extend PM2s functionality with official modules:
- pm2-logrotate: Automatic log rotation and compression
- pm2-web: Web-based monitoring dashboard
- pm2-monitor: Real-time metrics and alerts
- pm2-docker: Official Docker image for containerized deployments
Install any module with:
pm2 install <module-name>
Third-Party Integrations
- Docker: Run PM2 inside containers using
keymetrics/pm2:latest - GitHub Actions: Automate deployments using PM2s deploy feature
- Netlify/Vercel: Not applicable for PM2 these are serverless platforms
- UptimeRobot: Monitor your apps HTTP endpoint for availability
- Prometheus + Grafana: Visualize PM2 metrics with custom dashboards
Documentation and Learning Resources
- Official PM2 Documentation
- PM2 GitHub Repository
- Node.js Best Practices
- Nginx Configuration Guide
- DigitalOcean Node.js Production Guide
Sample Project Templates
Start with these GitHub templates:
Real Examples
Example 1: Production API Server
Scenario: A RESTful API serving 50,000 daily requests on a 4-core VPS.
Configuration (ecosystem.config.js):
module.exports = {
apps: [{
name: 'api-server',
script: './src/index.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_restarts: 5,
max_memory_restart: '1G',
error_file: '/var/log/api-server/err.log',
out_file: '/var/log/api-server/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
env_production: {
NODE_ENV: 'production',
PORT: 8080,
DB_URI: 'mongodb://localhost:27017/myapp',
JWT_SECRET: 'supersecret123'
}
}]
};
Deployment:
- Server: Ubuntu 22.04
- User:
nodeapp - Reverse Proxy: Nginx (port 80 ? 8080)
- SSL: Lets Encrypt via Certbot
- Auto-start: Enabled via systemd
- Monitoring: PM2 Web Dashboard + UptimeRobot
Result: 99.98% uptime over 6 months, 200ms average response time, zero unplanned restarts.
Example 2: Microservice Architecture
Scenario: Three Node.js services user service, order service, notification service running on one server.
Configuration:
module.exports = {
apps: [
{
name: 'user-service',
script: './services/user/index.js',
instances: 2,
exec_mode: 'cluster',
env_production: { PORT: 3001 }
},
{
name: 'order-service',
script: './services/order/index.js',
instances: 2,
exec_mode: 'cluster',
env_production: { PORT: 3002 }
},
{
name: 'notification-service',
script: './services/notification/index.js',
instances: 1,
exec_mode: 'fork',
env_production: { PORT: 3003 }
}
]
};
Deployment:
- Each service exposed via Nginx on different subpaths:
/api/users,/api/orders,/api/notify - Centralized logging to Elasticsearch
- PM2 saved on boot, logs rotated daily
Result: Independent scaling, fault isolation, and easier debugging. One service crash doesnt bring down others.
Example 3: CI/CD Pipeline with GitHub Actions
Scenario: Automatically deploy code to production on every push to main.
.github/workflows/deploy.yml:
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci --only=production
- name: Deploy via PM2
run: |
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP }} "
cd /var/www/myapp &&
git pull &&
npm ci --only=production &&
pm2 reload ecosystem.config.js --env production
"
Result: Zero-touch deployments. Code pushed ? live in under 90 seconds.
FAQs
Is PM2 better than nodemon?
PM2 and nodemon serve different purposes. Nodemon is designed for development it restarts your app on file changes. PM2 is designed for production it manages processes, clusters, logging, and auto-restarts. Use nodemon during development, PM2 in production.
Can PM2 manage non-Node.js applications?
Yes. PM2 can manage any executable Python scripts, PHP CLI apps, or shell scripts. Just specify the script path:
pm2 start my-script.py --name "python-app"
Does PM2 replace Nginx?
No. PM2 handles application process management and clustering. Nginx handles HTTP routing, SSL termination, static file serving, and security. Use both together for optimal performance and security.
Why does my app restart every 5 minutes?
This usually happens due to memory limits. Check if max_memory_restart is set too low. Also, look for memory leaks in your code. Use pm2 monit to monitor memory usage over time.
How do I update my app without downtime?
Use pm2 reload app-name. This restarts each instance one at a time, ensuring at least one instance is always handling requests. Works only with clustering enabled.
Can I use PM2 on Windows?
Yes, but its not recommended for production. PM2 works on Windows for development, but process management and auto-start features are unreliable. Use Windows Service or PM2 via WSL2 for production on Windows servers.
How do I check which apps are running under PM2?
Run pm2 list to see all managed apps. Use pm2 show app-name for detailed info about a specific app, including environment variables and restart history.
What happens if PM2 crashes?
PM2 is designed to be resilient. If the PM2 daemon crashes, your apps continue running theyre independent processes. Restart PM2 with pm2 resurrect to restore the saved process list.
Is PM2 free for commercial use?
Yes. PM2 is open-source under the MIT license and free for all uses, including commercial production environments.
Conclusion
PM2 is not just another Node.js tool its a production necessity. From automatic restarts and clustering to real-time monitoring and zero-downtime deployments, PM2 transforms how you run Node.js applications in the real world. Whether youre managing a single app or a fleet of microservices, PM2 provides the stability, scalability, and observability that bare node commands simply cannot match.
This guide has walked you through every critical aspect of using PM2: installation, configuration, clustering, logging, deployment, and optimization. Youve seen how to avoid common pitfalls, secure your environment, and integrate PM2 into modern DevOps workflows.
Remember: a well-managed Node.js application is not defined by its code its defined by its resilience. With PM2, youre no longer just running an app. Youre running a reliable, scalable, and production-ready service.
Start small. Apply one best practice at a time. Monitor your apps. Automate your deployments. And never again lose sleep over a crashed server.
PM2 is your ally in building robust Node.js applications. Use it wisely and your users will thank you.