How to Use Pm2 for Nodejs
How to Use PM2 for Node.js Node.js has become the backbone of modern web applications, powering everything from APIs and microservices to real-time chat platforms and backend systems. However, running Node.js applications in production comes with unique challenges—crashes, memory leaks, process management, and restart failures can bring down your entire system. This is where PM2, a production-grad
How to Use PM2 for Node.js
Node.js has become the backbone of modern web applications, powering everything from APIs and microservices to real-time chat platforms and backend systems. However, running Node.js applications in production comes with unique challengescrashes, memory leaks, process management, and restart failures can bring down your entire system. This is where PM2, a production-grade process manager for Node.js applications, becomes indispensable.
PM2 (Process Manager 2) is not just another toolits a comprehensive runtime environment designed to keep your Node.js applications alive, scalable, and observable. Whether youre managing a single app or a cluster of microservices across multiple servers, PM2 simplifies deployment, monitoring, logging, and auto-recovery. In this guide, well walk you through every aspect of using PM2 effectively, from installation to advanced clustering, best practices, real-world examples, and troubleshooting.
By the end of this tutorial, youll have the knowledge to deploy, monitor, and maintain Node.js applications with enterprise-grade reliability using PM2no matter your experience level.
Step-by-Step Guide
1. Installing PM2
Before you can use PM2, you must install it globally on your system. PM2 is distributed via npm (Node Package Manager), so ensure you have Node.js and npm installed. Verify your installation by running:
node -v
npm -v
If these commands return version numbers, youre ready to proceed. Install PM2 globally using:
npm install -g pm2
Once installed, verify the installation by checking the PM2 version:
pm2 -v
You should see the current version number (e.g., 5.3.0 or higher). If you encounter permission errors during installation, you may need to configure npm to use a different directory or use a Node version manager like nvm (Node Version Manager) for better control over your Node.js environment.
2. Starting a Node.js Application with PM2
Assume you have a basic Node.js application in a file named app.js:
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello, PM2!');
});
app.listen(port, () => {
console.log(Server running at http://localhost:${port});
});
To start this application with PM2, navigate to the directory containing app.js and run:
pm2 start app.js
PM2 will output a table showing the process details:
- Name: The name of the process (default is the filename)
- id: A unique identifier assigned by PM2
- mode: The execution mode (fork mode by default)
- pid: The operating system process ID
- status: Whether the process is online or stopped
- uptime: How long the process has been running
- memory: Current memory usage
- restarting: Number of restarts
- cpu: CPU utilization
- pm2 log: Path to the log file
At this point, your application is running in the background and will automatically restart if it crashes.
3. Naming Your Applications
By default, PM2 assigns the filename as the process name. For clarity, especially when managing multiple apps, assign a custom name using the --name flag:
pm2 start app.js --name "my-express-app"
Now, when you list your processes with pm2 list, youll see my-express-app instead of app.js. This improves readability and reduces confusion in complex deployments.
4. Starting Multiple Applications
Managing multiple Node.js apps manually is error-prone. PM2 allows you to define and manage multiple apps using a configuration file called ecosystem.config.js.
Create a file named ecosystem.config.js in your project root:
module.exports = {
apps: [{
name: 'api-server',
script: './src/api/app.js',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
},
{
name: 'worker-service',
script: './src/worker/index.js',
instances: 2,
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_memory_restart: '512M'
}]
};
This configuration defines two apps:
- api-server: A single-instance Express server in development mode.
- worker-service: A cluster-mode worker process with 2 instances for better performance.
Start all apps defined in the config file with:
pm2 start ecosystem.config.js
PM2 will read the configuration and start each app according to its settings. You can also start a specific app by name:
pm2 start ecosystem.config.js --only api-server
5. Using Cluster Mode for Better Performance
Node.js is single-threaded by default. This means a single instance of your app can only utilize one CPU core. On modern multi-core servers, this leads to underutilized hardware.
PM2s cluster mode allows you to spawn multiple instances of your app, each running on a separate CPU core. This dramatically improves throughput and resource utilization.
To enable cluster mode, set exec_mode: 'cluster' and define the number of instances:
instances: 'max' // Uses all available CPU cores
Or specify a fixed number:
instances: 4
Cluster mode works by having PM2 fork child processes that share the same server port. The operating system handles load balancing between them. This is transparent to your application codeno changes to your Express or Koa routes are needed.
Important: Cluster mode only works with applications that dont maintain state in memory (e.g., no in-memory session stores). For stateful apps, use external services like Redis.
6. Managing Processes: Start, Stop, Restart, Delete
PM2 provides intuitive commands to manage your applications:
- Start:
pm2 start app.js - Stop:
pm2 stop api-server(orpm2 stop 0to stop by ID) - Restart:
pm2 restart api-server - Delete:
pm2 delete api-server(removes from PM2s process list) - Delete all:
pm2 delete all - List all processes:
pm2 list - View logs in real time:
pm2 logs - View logs for a specific app:
pm2 logs api-server - Flush logs:
pm2 flush(clears all log files)
You can also monitor your apps in real time using the built-in dashboard:
pm2 monit
This opens a live terminal-based dashboard showing CPU, memory, and request rates per processideal for debugging performance issues on the fly.
7. Setting Up Auto-Start on Boot
One of PM2s most powerful features is its ability to restart your applications automatically after a server reboot.
Run the following command to generate a startup script:
pm2 startup
PM2 will detect your system (systemd, init, launchd, etc.) and output a command to run with sudo privileges. For example:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
Copy and execute this command exactly as shown. Then, save your current process list:
pm2 save
This command serializes your current process list to disk. On reboot, PM2 will automatically reload all apps listed in the saved snapshot.
Test this by rebooting your server:
sudo reboot
After the system comes back online, run pm2 list to confirm your apps are running again.
8. Logging and Log Rotation
PM2 automatically captures stdout and stderr from your applications and stores them in log files. By default, logs are stored in ~/.pm2/logs/ with filenames like app-name-out.log and app-name-error.log.
To view logs interactively:
pm2 logs
To follow logs in real time (like tail -f):
pm2 logs --raw
To view only the last 100 lines:
pm2 logs --lines 100
Log files can grow large over time. To prevent disk space issues, enable log rotation:
pm2 install pm2-logrotate
This plugin automatically rotates logs daily, compresses old logs, and deletes logs older than 30 days by default. You can customize its behavior by editing its config:
pm2 set pm2-logrotate:retain 100
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:max_size 10M
These settings ensure logs stay manageable without manual intervention.
9. Environment-Specific Configurations
Applications often behave differently in development, staging, and production environments. PM2 supports environment-specific configurations using env and env_[name] blocks in your ecosystem file.
Example:
module.exports = {
apps: [{
name: 'my-app',
script: './app.js',
env: {
NODE_ENV: 'development',
PORT: 3000,
DB_HOST: 'localhost'
},
env_production: {
NODE_ENV: 'production',
PORT: 8080,
DB_HOST: 'prod-db.example.com',
LOG_LEVEL: 'info'
}
}]
};
Start the app in production mode:
pm2 start ecosystem.config.js --env production
PM2 loads the env_production block and overrides the default env values. This eliminates the need for environment variables in shell scripts or external .env files.
10. Monitoring with PM2 Plus (Optional)
PM2 offers a cloud-based monitoring solution called PM2 Plus (formerly PM2 Plus), which provides real-time dashboards, alerting, error tracking, and performance analytics.
To enable it:
- Sign up at https://app.pm2.io
- Install the PM2 Plus agent:
npm install -g pm2-plus - Link your server:
pm2 plus - Follow the on-screen instructions to authenticate and link your server to your account.
Once linked, youll see your server and applications appear in the PM2 Plus dashboard with metrics like:
- Real-time CPU and memory graphs
- HTTP request rates and response times
- Event logs with error detection
- Alerts for high memory usage or crashes
PM2 Plus is free for up to 3 servers and is invaluable for teams managing production applications across multiple environments.
Best Practices
1. Always Use a Configuration File
Never rely on command-line flags for production deployments. Use ecosystem.config.js to define all settings in a version-controlled file. This ensures consistency across environments and makes deployments reproducible.
2. Never Run Node.js as Root
Running Node.js applications as the root user is a serious security risk. Create a dedicated system user for your application:
sudo adduser --disabled-login --gecos 'Node.js App' nodeapp
Then, run PM2 under this user:
sudo -u nodeapp pm2 start ecosystem.config.js
This limits the damage if your application is compromised.
3. Set Memory Limits
Node.js applications can leak memory over time. Use max_memory_restart to automatically restart your app if it exceeds a threshold:
max_memory_restart: '1G'
This prevents gradual memory bloat from causing system-wide slowdowns.
4. Use Cluster Mode on Multi-Core Servers
Always enable cluster mode on servers with 2+ CPU cores. Use instances: 'max' to automatically scale to available cores. This is the single most effective performance optimization for most Node.js apps.
5. Monitor Logs and Set Up Alerts
Regularly review logs using pm2 logs. Use PM2 Plus or integrate with external logging tools like Loggly, Datadog, or ELK stack for centralized logging. Set up email or Slack alerts for critical errors using PM2 Plus or custom scripts.
6. Use Health Checks
Integrate a simple health check endpoint in your app (e.g., /health) that returns 200 OK. Combine this with a reverse proxy like Nginx or a cloud load balancer to route traffic only to healthy instances.
7. Keep PM2 Updated
PM2 releases regular updates with performance improvements and bug fixes. Update it periodically:
npm update -g pm2
Always test updates in staging first.
8. Backup Your PM2 Snapshot
Run pm2 save after any change to your process list. This ensures your startup configuration is preserved. Consider backing up the snapshot file (~/.pm2/dump.pm2) as part of your server backup strategy.
9. Avoid File Watching in Production
While watch: true is useful during development, it can cause performance issues and unintended restarts in production. Disable it unless you have a specific reason to enable it.
10. Use Reverse Proxies for Production
PM2 is a process manager, not a web server. For production, always front your Node.js app with a reverse proxy like Nginx or Caddy. This provides:
- SSL termination
- Load balancing (if multiple PM2 instances)
- Static file serving
- Rate limiting and caching
Example Nginx config:
server {
listen 80;
server_name example.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;
}
}
Tools and Resources
Core PM2 Tools
- PM2 CLI: The primary interface for managing processes. Use
pm2 helpto explore all commands. - PM2 Logrotate: A plugin for automated log rotation and cleanup. Install with
pm2 install pm2-logrotate. - PM2 Plus: Cloud monitoring dashboard with real-time metrics and alerts. Free tier available.
- PM2 Runtime: A lightweight version of PM2 designed for Docker containers and edge deployments.
Integration Tools
- Nginx: Reverse proxy for SSL, caching, and load balancing.
- Systemd: Linux init system that PM2 integrates with for auto-start on boot.
- Docker: Use PM2 inside containers for consistent environments. Combine with
pm2-runtimefor better container management. - Redis: Use as an external session store when running in cluster mode.
- Loggly / Datadog / ELK: Centralized logging platforms for large-scale deployments.
- GitHub Actions / GitLab CI: Automate deployment workflows using PM2 commands.
Documentation and Learning Resources
- Official PM2 Documentation Comprehensive guide to all features.
- PM2 GitHub Repository Source code, issues, and community contributions.
- DigitalOcean Node.js + PM2 Tutorial Step-by-step production setup.
- Node.js Official Guides Best practices for building scalable apps.
- PM2 in 10 Minutes (YouTube) Quick visual walkthrough.
Recommended npm Packages for Production
- dotenv: Load environment variables from .env files.
- winston or pino: Advanced logging libraries that integrate well with PM2.
- helmet: Secure Express apps with HTTP headers.
- express-rate-limit: Prevent abuse with request throttling.
- cors: Handle cross-origin requests securely.
Real Examples
Example 1: Deploying a REST API with PM2
Imagine youre deploying a REST API built with Express and MongoDB. Heres your full workflow:
- Clone the repo:
git clone https://github.com/yourname/api-project.git - Install dependencies:
npm install - Create
ecosystem.config.js:
module.exports = {
apps: [{
name: 'api-v1',
script: './server.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development',
PORT: 3000,
MONGO_URI: 'mongodb://localhost:27017/myapp'
},
env_production: {
NODE_ENV: 'production',
PORT: 8080,
MONGO_URI: 'mongodb://prod-mongo.example.com:27017/myapp',
LOG_LEVEL: 'info'
}
}]
};
- Install PM2:
npm install -g pm2 - Start in production:
pm2 start ecosystem.config.js --env production - Save the process list:
pm2 save - Set up auto-start:
pm2 startup? run the provided sudo command - Install logrotate:
pm2 install pm2-logrotate - Configure Nginx to proxy requests to port 8080
- Test:
curl http://yourserver.com/api/users
After this, your API is running in cluster mode, auto-restarting on crash, logging properly, and surviving reboots.
Example 2: Running a Background Worker with PM2
Many apps need background jobssending emails, processing images, syncing data. Heres a simple worker:
// worker.js
const cron = require('node-cron');
const fs = require('fs');
cron.schedule('*/5 * * * *', () => {
fs.appendFileSync('./log.txt', Processed at ${new Date()}\n);
console.log('Worker: Processing task...');
});
console.log('Worker service started');
Add it to your ecosystem config:
{
name: 'data-worker',
script: './worker.js',
instances: 1,
exec_mode: 'fork',
autorestart: true,
max_memory_restart: '256M',
env: {
NODE_ENV: 'production'
}
}
Start it: pm2 start ecosystem.config.js --only data-worker
Now your worker runs reliably in the background, restarting if it fails, with logs you can monitor via pm2 logs data-worker.
Example 3: Docker + PM2 Runtime
For containerized deployments, use PM2 Runtime instead of the full PM2 package:
Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
Use pm2-runtime instead of node
CMD ["pm2-runtime", "server.js"]
Build and run:
docker build -t myapp .
docker run -p 3000:3000 myapp
PM2 Runtime is optimized for containers and handles signals properly, making it ideal for Kubernetes, Docker Compose, or cloud platforms like AWS ECS.
FAQs
1. Is PM2 better than Node.js native process management?
Yes. Node.jss built-in process management (e.g., using node app.js) offers no auto-restart, no logging, no clustering, and no boot persistence. PM2 adds all these features out of the box, making it far superior for production use.
2. Can PM2 manage non-Node.js applications?
Yes. PM2 can manage any executable, including Python scripts, Ruby apps, or shell scripts. For example: pm2 start script.py --interpreter python3.
3. Does PM2 work on Windows?
Yes, but with limitations. While PM2 runs on Windows, some features like auto-start on boot and cluster mode are not fully supported. For Windows production environments, consider using Windows Services or NSSM instead.
4. How do I update my app without downtime?
Use pm2 reload app-name. This performs a zero-downtime reload by starting new instances before stopping old ones. Requires cluster mode for multiple instances.
5. Why does my app restart every few minutes?
This usually indicates a memory leak or a misconfigured max_memory_restart. Check your logs with pm2 logs and monitor memory usage in pm2 monit. Consider profiling your app with Node.js built-in profiler or Clinic.js.
6. Can I use PM2 with TypeScript?
Yes. Install ts-node and use:
pm2 start src/app.ts --interpreter ts-node
Or compile to JavaScript first and run the built files.
7. How do I check which apps are running under PM2?
Use pm2 list to see all managed apps. Use pm2 show app-name for detailed info about a specific process.
8. Whats the difference between fork mode and cluster mode?
Fork mode runs a single instance of your app. Cluster mode spawns multiple instances across CPU cores, enabling better performance and scalability. Use cluster mode for web servers; fork mode for background workers.
9. Can PM2 restart apps based on HTTP error rates?
Not natively. However, you can integrate PM2 with external monitoring tools (like PM2 Plus or Prometheus + Alertmanager) to trigger restarts based on custom metrics.
10. Is PM2 secure?
Yes, when used correctly. Always run PM2 under a non-root user, keep it updated, avoid file watching in production, and use a reverse proxy. Never expose the PM2 dashboard to the public internet.
Conclusion
PM2 is not just a toolits a production-grade runtime environment that transforms how you deploy, monitor, and maintain Node.js applications. From automatic restarts and cluster scaling to log management and boot persistence, PM2 eliminates the operational friction that often accompanies Node.js deployments.
By following the steps outlined in this guidefrom installing PM2 and creating a configuration file to enabling cluster mode and securing your setupyouve equipped yourself with the knowledge to run Node.js applications with enterprise-grade reliability. Whether youre managing a single API endpoint or a fleet of microservices, PM2 provides the stability and observability your applications deserve.
Remember: The goal is not just to run your app, but to run it well. Use configuration files, avoid root privileges, monitor logs, and leverage tools like PM2 Plus and Nginx to build resilient systems. As your applications grow in complexity, PM2 will scale with youensuring uptime, performance, and peace of mind.
Start small. Automate everything. Monitor constantly. And let PM2 handle the heavy liftingso you can focus on building great software.