Start Processes
| Command | What it does |
|---|---|
| Start a script under PM2 (named after the file) | |
| Start it with a name you can use in every other command | |
| Everything after the bare goes to the script, not PM2 | |
| Run under PM2 | |
| Any package.json script the same way | |
| Non-Node scripts (bash, python, ruby) | |
| Restart on file changes (development only) | |
| Watch, but not these paths | |
| Restart the process when it passes 300 MB | |
| Flags for Node itself, not the script | |
| Scheduled restart (here 04:00 daily) | |
| Start everything defined in an ecosystem file | |
| Static file server for a build folder, SPA fallback to index.html |
More than a couple of flags belongs in an ecosystem file rather than your shell history; the PM2 ecosystem generator writes one from a form.
List and Status
| Command | What it does |
|---|---|
| Every process with status, CPU, memory and restart count ( and are the same) | |
| Full detail for one process: paths, logs, env, uptime ( is the same) | |
| The list as JSON, for scripts | |
| The same JSON, readable | |
| Check the PM2 daemon is up | |
| Full diagnostic dump for a bug report |
The restart counter ( in the list) climbing on its own means the app is crash-looping; read the error log before anything else.
Logs
PM2 captures each process's stdout and stderr to files under .
| Command | What it does |
|---|---|
| Stream all logs live, like for everything | |
| Only one process | |
| Start with the last 200 lines instead of 15 | |
| Error stream only ( for stdout only) | |
| Structured output, one JSON object per line | |
| Prefix each line with a timestamp | |
| Empty every log file ( for one) | |
| Log rotation module; without it the files grow forever | |
| Rotate when a file passes 10 MB | |
| Keep 14 rotated files | |
| Gzip rotated files |
PM2 does not rotate logs on its own, and a chatty app fills a disk quietly. Install on every server the first time you set one up.
Restart, Reload and Stop
| Command | What it does |
|---|---|
| Kill and start again; drops requests in flight | |
| Every process | |
| Zero-downtime restart, one instance at a time (cluster mode only; falls back to restart in fork mode) | |
| Restart and pick up the current shell environment | |
| Stop it but keep it in the list, so brings it back | |
| Stop everything | |
| Stop it and remove it from the list | |
| Empty the list | |
| Stop the PM2 daemon and every process it manages |
keeps the entry (status ); forgets it. After any change you want back after a reboot, run again.
Cluster Mode
Cluster mode runs several instances of the same Node app behind PM2's built-in load balancer, one per core with . The app needs no code changes as long as it does not keep local state.
| Command | What it does |
|---|---|
| One instance per CPU core | |
| Exactly four instances | |
| All cores but one | |
| Resize a running cluster to 8 instances | |
| Add two instances | |
| Roll through the instances with zero downtime |
Cluster mode is Node-only, since it uses the Node module. Sticky sessions and anything held in process memory (in-memory sessions, local caches) break across instances; move that state to Redis or the database first.
Save, Startup and Resurrect
Surviving a reboot is a two-step dance, and skipping the second step is the classic mistake.
| Command | What it does |
|---|---|
| Detect the init system and print the install command; it does nothing else | |
| (paste the printed command) | The line it printed; this installs the boot hook |
| Write the current process list to ; this is what boot restores | |
| Save even when the list is empty | |
| Restore the saved list by hand, without rebooting | |
| Remove the boot hook | |
| Delete the saved list |
So the full sequence is: , run the command it printed, get your apps running the way you want, then . The hook restores whatever the last captured, so rerun it after adding, deleting or renaming processes.
Windows
only knows Linux and macOS init systems. On Windows it prints nothing useful, so PM2 has to be installed as a Windows service instead.
| Command | What it does |
|---|---|
| Same install; lands in npm's global bin folder | |
| Community helper that registers the boot hook | |
| Install the hook, then as usual | |
| Same streaming; the files live under |
The other option is , which registers PM2 itself as a Windows service so it starts before anyone logs in. Either way is still what decides which apps come back. Everything else (, , , , ecosystem files) behaves the same; paths in an ecosystem file want forward slashes or escaped backslashes.
Environment Variables
| Command | What it does |
|---|---|
| Environment from the shell, captured at start | |
| Use the block from the ecosystem file | |
| Re-read the shell environment; a plain restart keeps the old one | |
| Print the environment of process id 0 |
PM2 snapshots the environment when a process first starts and reuses it on every restart. Changing a variable in the shell or in does nothing until you restart with or delete and start fresh. This surprises everyone once.
Node Version and Interpreter
The PM2 daemon keeps the Node version it was started with. Switching versions with nvm changes your shell, not the daemon, so apps keep running on the old binary until you reload the daemon.
| Command | What it does |
|---|---|
| Shows the interpreter path and Node version for one process | |
| Shows the Node version the PM2 daemon itself runs on | |
| Reload the daemon on the current Node and bring processes back | |
| Use whatever is first on PATH | |
| Pin one app to an exact Node build | |
| Run TypeScript directly (install yourself first) | |
| A compiled binary needs no interpreter |
In an ecosystem file the same settings are the and fields, which is the sane place to pin a version per app:
{
name: "api",
script: "./server.js",
interpreter: "/home/deploy/.nvm/versions/node/v22.11.0/bin/node",
}After an nvm upgrade, is only half the job: the boot hook installed by has the old PATH written into it, so run , , the command it prints, then again. PM2 no longer bundles , so TypeScript needs (or a local install plus ); compiling to JavaScript first and running the output is steadier in production.
Ecosystem File
holds everything the start flags express, in a file you can commit. writes a sample, or the PM2 ecosystem generator builds one from a form.
module.exports = {
apps: [{
name: "api",
script: "./server.js",
instances: "max",
exec_mode: "cluster",
max_memory_restart: "300M",
args: "--port 3000",
env: { NODE_ENV: "development" },
env_production: { NODE_ENV: "production" },
}],
};| Command | What it does |
|---|---|
| Start every app in the file | |
| Just one of them | |
| Apply the block | |
| Reload everything the file defines | |
| Restart and re-read the file's env blocks |
Monitoring
| Command | What it does |
|---|---|
| Live dashboard in the terminal: CPU, memory and logs per process | |
| Uptime, restart count, log paths, script path for one process | |
| The quick overview; watch the memory and columns |
is the fastest answer to "which process is eating the CPU". For alerting and history, PM2's hosted monitoring () exists, but plain over SSH covers day-to-day checks.
Install and Upgrade
| Command | What it does |
|---|---|
| Install PM2 globally; the binary goes in npm's global bin | |
| Print that global prefix when the shell cannot find | |
| Check the installed version | |
| Reload the PM2 daemon in place after upgrading pm2 itself, keeping processes alive | |
| The full upgrade sequence | |
| Install a PM2 module (log rotation, metrics) |
Upgrading the npm package alone changes nothing for running apps, since the old daemon stays in memory. is what swaps it. Under nvm, PM2 is installed per Node version, so a new Node version means installing PM2 again.
Deployment
| Command | What it does |
|---|---|
| First-time setup of the deploy target defined in the ecosystem file | |
| Pull, install and reload on the target servers |
reads a section in the ecosystem file (host, repo, path, post-deploy command) and works fine for simple git-based deploys. Teams that outgrow it usually move to CI plus over SSH.
If you would rather have the init system own the process, with proper dependencies and journald logging, the pm2 to systemd converter turns an ecosystem file into unit files, and the systemctl cheat sheet covers managing them.
Gotchas
- alone does nothing at boot. It prints a command; run that command, then . The saved dump is what gets restored, so save again after every change to the list.
- is only zero-downtime in cluster mode with two or more instances. In fork mode it is just a restart with a friendlier name.
- Restarts keep the environment from the first start. New or changed variables need , or a delete and a fresh start.
- Logs are never rotated by default. before the disk fills, and when it already has.
- in production causes restart loops when the app writes into its own directory (logs, uploads). Use , or better, no watch at all outside development.
- in cron, CI or GitHub Actions usually means npm's global bin is not on that context's PATH; use the absolute path to the binary.
- Switching Node with nvm does not move the apps. The daemon holds the old version until , and the boot hook holds the old PATH until you rerun and .
- takes down the daemon and every app with it. To remove one app, .