Jesse A. Green / notebook

PM2 User Guide

Generated June 2026 from Unitech/pm2 at ba62cae

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

PM2 is a production process manager for Node.js and Bun applications with a built-in load balancer. It keeps your applications alive forever, reloads them with zero downtime, manages their logs, and lets you control everything from a single command-line tool. PM2 can also run Python, Ruby, bash, and any binary in your $PATH.

Starting an application in production is as simple as:

pm2 start app.js

Your app is now daemonized, monitored, and kept alive across crashes and server reboots.

This guide covers everything you need to install PM2, run and manage your applications, scale them across CPU cores, stream their logs, survive server restarts, and troubleshoot the common issues. It is written against PM2 7.0.1 and is written from the source code.

Note

PM2 manages a background daemon (internally called "God") that owns your application processes. The pm2 command you type is a thin client that talks to this daemon. The daemon keeps running after your terminal closes — that is what keeps your apps alive.


1. Quick Start

Install PM2 globally, start an app, and inspect it — three commands:

npm install pm2 -g
pm2 start app.js
pm2 ls

You will see a process table like this:

┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ app                │ fork     │ 0    │ online    │ 0%       │ 41.2mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

From here, the everyday commands are:

pm2 logs            # stream logs from all apps
pm2 restart app     # restart the app named "app"
pm2 stop app        # stop it (keeps it in the list)
pm2 delete app      # stop and remove it from the list
pm2 monit           # live dashboard of CPU/memory/logs

Tip

To make PM2 and your apps survive a server reboot, run pm2 startup once, then pm2 save after your apps are running. See Section 8.


2. Installation

2.1 Requirements

Requirement Detail
Node.js 18.0.0 or newer (declared in engines)
Bun 1.1.25 or newer (PM2 refuses to start on older Bun — cluster support)
Operating systems Linux, macOS, Windows
Privileges A normal user account. Root/sudo is only needed to install a boot startup script

2.2 Install with a package manager

npm

npm install pm2 -g

Bun

bun install pm2 -g

Yarn

yarn global add pm2

After installation, confirm the version:

pm2 --version
7.0.1

2.3 Bun-only systems

If you have Bun installed but no Node.js, PM2's #!/usr/bin/env node shebang has nothing to resolve. Symlink node to bun so the shebang lands on Bun's Node-compatibility runtime:

sudo ln -s $(which bun) /usr/local/bin/node

Warning

PM2 will throw PM2 cannot run on Bun version < 1.1.25 (cluster support) and exit if your Bun is older than 1.1.25. Upgrade Bun before installing PM2.

2.4 Installing a development build

To run the bleeding-edge development branch instead of the npm release:

npm install git://github.com/Unitech/pm2.git#development -g

2.5 The four binaries

Installing PM2 puts four executables on your PATH. You will mostly use pm2, but the others matter for development and containers:

Binary Purpose
pm2 The main process manager and CLI (everything in this guide)
pm2-dev Development mode: starts one app, watches for file changes, streams logs in the foreground
pm2-runtime A drop-in replacement for node in containers — runs in the foreground and exits with the app
pm2-docker Alias of pm2-runtime, kept for backward compatibility

Note

PM2 stores all of its state — logs, pids, the saved process list, and its control sockets — in a home directory at ~/.pm2. You can relocate it with the PM2_HOME environment variable (see Section 13).


3. Starting Applications

The pm2 start command is the entry point for almost everything. It accepts a script, an application name, a process id, an ecosystem config file, or a list of these.

pm2 start <name|namespace|file|ecosystem|id...>

3.1 Start a script

pm2 start app.js
[PM2] Starting /home/user/app/app.js in fork_mode (1 instance)
[PM2] Done.

3.2 Give the app a name

By default PM2 names the process after the script file (without its extension), e.g. app.js becomes app. Override it with --name:

pm2 start app.js --name api

Tip

Always name your apps explicitly in production. You will be typing pm2 restart api far more often than you expect, and a clear name beats a numeric id.

3.3 Start non-Node programs

PM2 is not limited to Node.js. Use --interpreter to run any language, or --interpreter none to run a binary directly:

pm2 start app.py --interpreter python3
pm2 start worker.rb --interpreter ruby
pm2 start script.sh --interpreter bash
pm2 start ./my-binary --interpreter none

The -x / --execute-command flag is shorthand for running a program with the fork system.

3.4 Pass arguments to your app

Everything after a -- separator is passed through to your script, not to PM2:

pm2 start app.js --name api -- --port 8080 --verbose

Here --port 8080 --verbose are your application's arguments; --name api is PM2's.

3.5 Pass arguments to the interpreter (Node)

Use --node-args (alias --interpreter-args) for flags that go to Node itself:

pm2 start app.js --node-args="--max-old-space-size=2048 --trace-warnings"

3.6 Start from standard input

Pipe a JSON process definition straight into pm2 start -:

cat process.json | pm2 start -

3.7 Restart-on-start behavior

If you pm2 start a script that is already in the process list and currently stopped or errored, PM2 restarts it instead of creating a duplicate. To force a brand-new second instance of the same script, add -f / --force:

pm2 start app.js -f
[PM2][ERROR] Script already launched, add -f option to force re-execution

(That error is what you see without -f.)


4. Managing Running Applications

Once apps are running, you manage them by name, id, namespace, the keyword all, or a regex wrapped in slashes (e.g. /api-.*/).

4.1 The core lifecycle commands

Command What it does
pm2 restart <app> Kill and start the process again (brief downtime)
pm2 reload <app> Zero-downtime rolling restart (cluster mode only — see Section 5)
pm2 stop <app> Stop the process but keep it in the list (status becomes stopped)
pm2 delete <app> (alias pm2 del) Stop and remove the process from the list entirely
pm2 start <app> Start a stopped process again

Examples:

pm2 restart api
pm2 stop 0
pm2 restart all
pm2 delete all
pm2 restart /worker-.*/      # regex: every app whose name matches

Important

stop keeps the application's configuration in PM2's list so you can start it again later. delete forgets it entirely — you would need the original pm2 start command (or your ecosystem file) to bring it back.

4.2 Restart, reload, and the environment

By default, restart and reload do not refresh environment variables — your app keeps the environment it was first started with. This is intentional, so an accidental restart never silently changes config. To pull in the current environment, add -a / --update-env:

pm2 restart api --update-env
Use --update-env to update environment variables

(That message is PM2 reminding you that the environment was left unchanged.)

4.3 Scaling instances in cluster mode

pm2 scale api 4        # run exactly 4 instances of "api"
pm2 scale api +2       # add 2 more instances

4.4 Restart counters and limits

PM2 tracks how many times each app has restarted. Reset the counters with:

pm2 reset api
pm2 reset all

Control automatic-restart behavior at start time:

Flag Effect
--max-restarts [count] Give up after restarting this many times
--restart-delay <ms> Wait this long between restarts
--exp-backoff-restart-delay <ms> Use exponential backoff between restarts (delay grows after each failure)
--no-autorestart Never restart the app automatically
--stop-exit-codes <codes...> Treat these exit codes as clean — do not autorestart
--max-memory-restart <mem> Restart if memory exceeds this (e.g. 300M, 1G)
pm2 start worker.js --max-memory-restart 300M --exp-backoff-restart-delay 100

Tip

--exp-backoff-restart-delay is the best choice for a flapping app. Instead of hammering restarts in a tight loop, PM2 progressively widens the delay, giving a failing dependency (a database, an upstream API) time to recover. The backoff resets after the app stays up for 30 seconds.

4.5 Sending signals

pm2 sendSignal SIGUSR2 api      # by name
pm2 sendSignal SIGUSR2 0        # by id

4.6 Sending data to a process

pm2 send 0 "hello from pm2"     # write a line to process 0's stdin
pm2 attach 0                    # attach your terminal to process 0's stdin/stdout

Note

pm2 send and pm2 attach only work for apps running in fork mode. Cluster-mode processes do not have a shared stdin to write to.


5. Cluster Mode: Load Balancing & Zero-Downtime

Cluster mode runs multiple identical copies of your Node.js app and load-balances incoming HTTP/TCP/UDP connections across them using Node's built-in cluster module. This increases throughput on multi-core machines and lets you reload with zero downtime.

5.1 Start in cluster mode

The -i / --instances flag turns on cluster mode:

pm2 start api.js -i 4        # 4 instances
pm2 start api.js -i max      # one instance per CPU core
pm2 start api.js -i -1       # all cores except one
pm2 start api.js -i 0        # same as 'max'
[PM2] Starting /home/user/api.js in cluster_mode (4 instances)
[PM2] Done.

Important

Cluster mode requires that your application can run as multiple independent processes — typically a stateless HTTP/TCP server. Each instance receives a different value in the NODE_APP_INSTANCE environment variable (configurable via instance_var) so you can tell them apart.

5.2 Zero-downtime reload

pm2 reload api
pm2 reload all

reload restarts instances one at a time: it spawns a new worker, waits for it to start listening, then shuts down the old one. At least one instance is always serving traffic, so users never see a dropped connection.

By default PM2 waits for the new worker's listening event. If your app needs to do setup work before it is truly ready, opt into the explicit ready signal:

pm2 start api.js -i 4 --wait-ready --listen-timeout 10000

Then, inside your application, tell PM2 when you are ready:

// inside api.js, after your server is fully initialized
process.send('ready');

Warning

pm2 reload only performs a true zero-downtime rolling restart for apps in cluster mode. For a fork-mode app, reload falls back to a plain restart (with downtime). If zero-downtime matters, start with -i.

5.3 Graceful shutdown

When PM2 stops a process it sends SIGINT first, waits up to kill_timeout milliseconds (default 1600ms), then sends SIGKILL. Handle SIGINT to close connections cleanly:

process.on('SIGINT', () => {
  server.close(() => process.exit(0));
});

Give slow-draining apps more time with --kill-timeout:

pm2 start api.js --kill-timeout 5000

You can also ask PM2 to shut the app down via an IPC message instead of a signal — useful on Windows where signals are unreliable:

pm2 start api.js --shutdown-with-message

Your app then listens for the shutdown message:

process.on('message', (msg) => {
  if (msg === 'shutdown') { /* clean up */ process.exit(0); }
});

6. Inspecting Processes

6.1 Listing

Command Output
pm2 list (aliases ls, l, ps, status) The standard process table
pm2 jlist The full process list as raw JSON (for scripts)
pm2 prettylist The process list as prettified JSON
pm2 list --mini-list (-m) A compact, unformatted list
pm2 ls
pm2 jlist | jq '.[].name'

Sort the list with --sort:

pm2 ls --sort name:asc
pm2 ls --sort memory:desc

6.2 Describing one process

pm2 describe (aliases desc, info, show) prints every detail of a process — its script path, log files, environment, restart count, uptime, exec mode, and more:

pm2 describe api
pm2 show 0

Get just the pid, or the environment, of a process:

pm2 pid api          # print the OS pid(s)
pm2 id api           # print PM2's internal id by name
pm2 env 0            # print the environment variables of process 0

6.3 Live monitoring dashboards

pm2 monit            # terminal dashboard: CPU, memory, and logs per app
pm2 dashboard        # (alias 'dash') richer dashboard with monitoring + logs
pm2 imonit           # legacy termcaps monitor

6.4 Host vitals (system monitoring)

Enable a monitoring "speedbar" for the host machine's CPU, memory, and disk:

pm2 set pm2:sysmonit true
pm2 update

Then query system information directly:

pm2 slist            # system info as JSON
pm2 slist --tree     # as a readable tree
pm2 sysmonit         # start the system-monitoring daemon

7. Log Management

PM2 captures the stdout and stderr of every app and writes them to files in ~/.pm2/logs/, while also letting you stream them live.

7.1 Streaming logs

pm2 logs                  # stream logs from all apps
pm2 logs api              # only the "api" app
pm2 logs --lines 200      # show the last 200 lines first (default 15)
pm2 logs --err            # only stderr
pm2 logs --out            # only stdout
pm2 logs --timestamp      # prefix each line with a timestamp
pm2 logs --json           # structured JSON log lines
pm2 logs --format         # key=value formatted output
pm2 logs --raw            # raw output, no PM2 framing
pm2 logs --nostream       # print recent logs and exit (don't follow)
pm2 logs api --highlight ERROR   # highlight matching text

7.2 Managing log files

pm2 flush                 # empty all log files
pm2 flush api             # empty only this app's logs
pm2 reloadLogs            # reopen log files (use after external log rotation)

7.3 Log formatting at start time

Flag Effect
--log <path> (-l) Combine stdout and stderr into one file
--output <path> (-o) stdout log file
--error <path> (-e) stderr log file
--log-type json Write logs as JSON objects
--log-date-format <fmt> Prefix each line with a timestamp in this format
--time Enable timestamped logging
--merge-logs In cluster mode, merge all instances into one pair of log files
--disable-logs Do not store logs at all
pm2 start api.js -i 4 --merge-logs --log-date-format "YYYY-MM-DD HH:mm:ss"

Tip

Without --merge-logs, a 4-instance cluster app produces 8 log files (4 out + 4 err). With it, you get just one stdout and one stderr file — much easier to tail.

7.4 Automatic log rotation

PM2's built-in log files grow forever. Install the pm2-logrotate module to cap and rotate them:

pm2 install pm2-logrotate

You can also drop a system logrotate configuration:

pm2 logrotate

8. Keeping Apps Alive Across Reboots (Startup & Save)

PM2 can generate an init-system service so that the daemon and your saved apps come back automatically after a reboot.

8.1 Generate and enable the startup script

pm2 startup

PM2 detects your init system and prints a command to run (usually with sudo). Run that command, and PM2 registers itself to boot.

Init systems supported: systemd, upstart, systemv, openrc, launchd, rcd, rcd-openbsd, smf. You can also name one explicitly:

pm2 startup systemd
pm2 startup launchd

Useful startup options:

Flag Purpose
-u <username> Run the service as this user
--hp <home path> Set the home path used in the generated script
--service-name <name> Name the generated service
--wait-ip Wait for full network connectivity before launching PM2 (systemd)

8.2 Freeze the current process list

After your apps are running the way you want, save them so they are restored on boot:

pm2 save
[PM2] Saving current process list...
[PM2] Successfully saved in /home/user/.pm2/dump.pm2

Important

pm2 startup only registers the boot hook. It does not record which apps to start — pm2 save does that. Always run pm2 save after starting or changing your apps, or they will not come back after a reboot.

8.3 Restore and remove

pm2 resurrect            # manually restore the saved process list
pm2 unstartup            # remove the boot hook
pm2 cleardump            # empty the saved process list

pm2 save (which is an alias of pm2 dump) writes to ~/.pm2/dump.pm2 and keeps a .bak copy. If the live list is empty, PM2 refuses to overwrite a non-empty dump unless you force it:

pm2 dump --force

9. Ecosystem Configuration Files

Typing long pm2 start commands does not scale. An ecosystem file declares all your apps and their settings in one place. Generate a template with:

pm2 ecosystem            # creates ecosystem.config.js
pm2 init                 # (alias)
pm2 ecosystem simple     # a minimal template

A typical ecosystem.config.js:

module.exports = {
  apps: [
    {
      name: 'api',
      script: './api.js',
      instances: 'max',
      exec_mode: 'cluster',
      watch: false,
      max_memory_restart: '300M',
      env: {
        NODE_ENV: 'development',
        PORT: 3000
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 8080
      }
    },
    {
      name: 'worker',
      script: './worker.js',
      instances: 1,
      cron_restart: '0 3 * * *',
      autorestart: true
    }
  ]
};

Start, restart, or reload everything in the file:

pm2 start ecosystem.config.js
pm2 start ecosystem.config.js --only api          # just one app
pm2 startOrRestart ecosystem.config.js
pm2 startOrReload ecosystem.config.js             # zero-downtime
pm2 startOrGracefulReload ecosystem.config.js

9.1 Selecting an environment

The --env flag injects a named environment block (env_<name>) from the file:

pm2 start ecosystem.config.js --env production
pm2 restart api --env production --update-env

In the example above, --env production merges the env_production block over the base env.

Note

--env only works when starting from an ecosystem file. pm2 reload api --env production without the file will fail with "Using --env [env] without passing the ecosystem.config.js does not work".

9.2 Full field reference

These are the fields you can set per app. They mirror the options available on the pm2 start command line (in snake_case).

Field Default Description
name script name Name used to reference the app
script — Path to the script or binary to run
args — Arguments passed to the script
interpreter node Interpreter (python, ruby, bash, or none for a binary)
interpreter_args / node_args — Arguments passed to the interpreter
cwd start dir Working directory for the process
instances 1 Number of instances (use max or 0 for all cores)
exec_mode fork fork or cluster
watch false Restart on file change; can be an array of paths
ignore_watch — Paths/regexes to ignore while watching
max_memory_restart — Restart when memory exceeds this (e.g. 300M)
max_restarts — Max restarts before giving up
min_uptime — Minimum uptime before a start is considered successful
restart_delay 0 Delay (ms) before restarting after exit
exp_backoff_restart_delay — Exponential backoff base delay (ms)
autorestart true Restart automatically on crash
autostart true Start automatically when added
stop_exit_codes — Exit codes that skip autorestart
cron_restart — Cron pattern for scheduled restarts
kill_timeout 1600 ms to wait after SIGINT before SIGKILL
listen_timeout — ms to wait for the app to be ready after reload
wait_ready false Wait for process.send('ready') instead of the listening event
shutdown_with_message false Send a shutdown IPC message instead of a signal
merge_logs false Merge cluster instance logs into one file
log_date_format — Timestamp format for log lines
output / error ~/.pm2/logs/... stdout / stderr log file paths
disable_logs false Disable log storage
log_type — json for structured logs
namespace default Group apps under a namespace
env — Environment variables to inject
port — Shortcut to inject a PORT env variable
instance_var NODE_APP_INSTANCE Env var holding each instance's id
increment_var — Env var incremented per cluster instance
filter_env — Strip matching env vars from the process
uid / gid — Run the process as this user / group
source_map_support — Force source-map support on or off

9.3 Writing a config from the command line

The -w / --write flag dumps the resolved configuration of a pm2 start to a <name>-pm2.json file in the current directory, which you can keep as a starting point:

pm2 start api.js --name api -i 4 --write

10. Namespaces

Namespaces group related apps so you can act on them together. Assign one at start time:

pm2 start api.js --namespace backend
pm2 start worker.js --namespace backend

Then operate on the whole group by name:

pm2 restart backend
pm2 stop backend
pm2 delete backend

11. Development Mode (pm2-dev)

For local development, pm2-dev runs a single app in the foreground, watches for file changes, restarts automatically, and streams logs to your terminal. Press Ctrl-C to stop everything.

pm2-dev app.js
pm2-dev start app.js

Options:

Flag Effect
--raw Raw log output
--timestamp Prefix logs with a timestamp
--node-args <args> Pass arguments to Node
--ignore [files] Comma-separated files to ignore while watching (node_modules is always ignored)
--post-exec [cmd] Run a command after each restart
--silent-exec Suppress the post-exec command's output
--interpreter <name> Use a non-Node interpreter
--env [name] Select an env_<name> block
--auto-exit Exit when all processes are stopped/errored or none launched

Note

pm2-dev uses a separate home directory (~/.pm2-dev) so it never interferes with your production pm2 process list.

11.1 Watch mode in the main CLI

You can also enable watching with the regular pm2 command:

pm2 start api.js --watch
pm2 start api.js --watch --ignore-watch="node_modules logs" --watch-delay 1000

Toggle watching on an already-running app:

pm2 restart api --watch       # turn watching on/off
pm2 stop api --watch          # stop watching

12. Running in Containers (pm2-runtime)

In a Docker container you usually want a foreground process that exits when your app dies, so the container's lifecycle matches the app's. That is exactly what pm2-runtime provides — a drop-in replacement for node.

FROM node:20
WORKDIR /app
COPY . .
RUN npm install pm2 -g && npm install
CMD ["pm2-runtime", "npm", "--", "start"]

Or point it at your app or ecosystem file directly:

CMD ["pm2-runtime", "app.js", "-i", "max"]
CMD ["pm2-runtime", "ecosystem.config.js"]

Key pm2-runtime options:

Flag Effect
-i --instances <n> Run N load-balanced instances
--watch Watch and restart on file change
--no-autorestart Disable automatic restart
--max-memory-restart <mem> Restart above a memory threshold
--web [port] Expose a process web API (default port 9615)
--delay <seconds> Delay startup of the config by N seconds
--no-auto-exit Do not exit when all apps are stopped
--json / --format / --raw Log output format
--only <app> Only run one app from the configuration

Tip

pm2-runtime streams your app's logs to the container's stdout/stderr, which is what Docker, Kubernetes, and your log aggregator expect. There is no separate pm2 logs step inside the container.


13. Environment Variable Reference

These environment variables change PM2's behavior. The most useful ones for everyday users:

Variable Default Purpose
PM2_HOME ~/.pm2 Directory for PM2's logs, pids, sockets, and saved list
PM2_KILL_TIMEOUT 1600 ms between SIGINT and SIGKILL when stopping a process
PM2_KILL_SIGNAL SIGINT Signal sent first when stopping a process
PM2_GRACEFUL_TIMEOUT 8000 ms to wait for graceful shutdown during reload
PM2_GRACEFUL_LISTEN_TIMEOUT 3000 ms to wait for the listening/ready event on reload
PM2_CONCURRENT_ACTIONS 2 How many apps PM2 starts/restarts/reloads in parallel
PM2_LOG_DATE_FORMAT YYYY-MM-DDTHH:mm:ss Default timestamp format for logs
PM2_DISCRETE_MODE — Suppress the PM2 startup banner
PM2_SILENT — Hide all PM2 messages (same as --silent)
PM2_HOME overrides — Individual paths can be overridden with PM2_* variants

Note

Setting PM2_HOME lets you run multiple independent PM2 instances on one machine (for example, one per deployed service or per user). Each instance has its own daemon, sockets, and process list.


14. Updating PM2

When you upgrade the PM2 package, the in-memory daemon is still running the old version. Refresh it without losing your apps:

npm install pm2@latest -g
pm2 update
>>>>>>>>>> PM2 updated

pm2 update saves your process list, restarts the daemon with the new code, and restores all your apps. PM2 also warns you automatically when the running daemon is out of date:

>>>> In-memory PM2 is out-of-date, do:
>>>> $ pm2 update

pm2 deepUpdate performs a deeper update of PM2 itself when a plain update is not enough.


15. Application Versioning & Deployment

If your app is a git checkout, PM2 can move it along its history and restart it:

pm2 pull api                 # pull the latest commit and restart
pm2 pull api <commit_id>     # check out a specific commit and restart
pm2 forward api              # move to the next commit
pm2 backward api             # roll back to the previous commit

PM2 also ships a declarative deploy system driven by the deploy block of an ecosystem file:

pm2 deploy ecosystem.config.js production setup
pm2 deploy ecosystem.config.js production

16. Modules

PM2 modules are background apps managed by PM2 itself (log rotation, monitoring probes, and more).

pm2 install pm2-logrotate            # install and run a module
pm2 install <git:// url>             # install from a git URL
pm2 module:update pm2-logrotate      # update a module
pm2 uninstall pm2-logrotate          # stop and remove a module
pm2 module:generate my-module        # scaffold a new module in the current folder

Module configuration uses the set / get commands with a module:key syntax:

pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30
pm2 get pm2-logrotate:max_size
pm2 conf pm2-logrotate               # view/edit module config
pm2 unset pm2-logrotate:max_size

17. Serving Static Files

PM2 can run a static HTTP file server as a managed process:

pm2 serve ./public 8080
pm2 serve ./dist 8080 --spa                       # always serve index.html
pm2 serve ./public 8080 --basic-auth-username admin --basic-auth-password secret
pm2 serve ./files 8080 --ftp                      # directory listing

pm2 serve (alias pm2 expose) keeps the server alive like any other app and shows up in pm2 ls.


18. PM2+ Monitoring (Optional)

PM2+ is a hosted dashboard (at app.pm2.io) for monitoring apps across servers. It is entirely optional.

pm2 link <secret> <public>       # connect this machine to a PM2+ bucket
pm2 monitor                      # start monitoring (opens the dashboard flow)
pm2 unmonitor                    # stop monitoring
pm2 open                         # open the dashboard in a browser
pm2 unlink                       # disconnect from PM2+
pm2 plus                         # enable PM2+ (alias 'register')
pm2 login                        # log in to PM2+
pm2 logout                       # log out

Note

You never need PM2+ to use PM2. All process management, clustering, logging, and startup features described in this guide work completely offline.


19. CPU & Memory Profiling

pm2 profile:cpu 10               # profile CPU for 10 seconds
pm2 profile:mem 10               # sample heap memory for 10 seconds

Deep monitoring (V8 metrics, event-loop inspector, transaction tracing) can be enabled at start:

pm2 start api.js --deep-monitoring

This is equivalent to --v8 --event-loop-inspector --trace. Tracing requires OpenTelemetry packages:

pm2 install-otel                 # install OpenTelemetry tracing packages
pm2 uninstall-otel               # remove them

20. Shell Completion

Install tab-completion for the pm2 command:

pm2 completion install

After reloading your shell, pressing Tab completes commands and your app names.


21. Generating a Diagnostic Report

When asking for help, attach a full diagnostic report:

pm2 report

This prints PM2's version, your Node version, environment, managed-app count, and daemon uptime — exactly what the maintainers ask for on the issue tracker.


22. Stopping the Daemon

To stop the PM2 daemon entirely — killing all managed apps with it:

pm2 kill
[PM2] [v] All Applications Stopped
[PM2] [v] PM2 Daemon Stopped

The daemon starts again automatically the next time you run any pm2 command. To check whether it is alive without starting apps:

pm2 ping
[PM2] pong

23. Command Quick Reference

Lifecycle

Command Description
pm2 start <app> Start and daemonize an app
pm2 restart <app> Restart an app
pm2 reload <app> Zero-downtime reload (cluster mode)
pm2 stop <app> Stop an app (keep in list)
pm2 delete <app> Stop and remove an app
pm2 scale <app> <n> Scale a cluster app to N instances
pm2 reset <app> Reset restart counters

Inspection

Command Description
pm2 list / ls / ps / status List processes
pm2 jlist / prettylist List as JSON
pm2 describe <app> / show / info Detail one process
pm2 monit / dashboard Live dashboard
pm2 logs Stream logs
pm2 pid <app> / id <app> / env <id> Pid / id / environment
pm2 slist System info as JSON

Persistence & system

Command Description
pm2 startup / unstartup Manage the boot hook
pm2 save / dump Freeze the process list
pm2 resurrect Restore the saved list
pm2 update / deepUpdate Refresh the in-memory daemon
pm2 kill / ping Stop / probe the daemon

Config, logs & modules

Command Description
pm2 ecosystem / init Generate a config file
pm2 set / get / unset / conf Manage configuration
pm2 flush / reloadLogs Manage log files
pm2 install / uninstall / module:update Manage modules
pm2 serve <path> <port> Serve static files

Getting help

pm2 --help                # all commands and options
pm2 <command> --help      # help for one command
pm2 examples              # printed usage examples

24. Troubleshooting

Error: Script already launched, add -f option to force re-execution

Cause — You tried to pm2 start a script that is already in the process list and online. PM2 prevents accidental duplicates.

Solution — To restart it, use pm2 restart <name>. To deliberately run a second copy, add -f:

pm2 start app.js -f

Prevention — Reference apps by name (pm2 restart api) instead of re-running pm2 start with the script path.


Error: Interpreter <name> is NOT AVAILABLE in PATH

Cause — PM2 cannot find the interpreter you specified (or the one inferred from the file extension). This is the most common cause behind issues like a Python or Ruby script that "stopped working" after a PM2 upgrade.

Solution — Make sure the interpreter is installed and on the PATH of the user running PM2. Specify it explicitly:

pm2 start app.py --interpreter python3
which python3        # confirm it resolves

Prevention — Pin the interpreter in your ecosystem file's interpreter field so it does not rely on extension inference.


Problem: pm2 start npm -- start does not behave as expected

Cause — Starting an npm script through PM2 requires passing the npm sub-command after the -- separator so it reaches npm rather than PM2.

Solution — Use the explicit form, and name it:

pm2 start npm --name myapp -- start

In containers, the same pattern works with pm2-runtime:

pm2-runtime npm -- start

Prevention — Always name the process and keep the -- separator before the npm sub-command.


Problem: My app restarts in an endless loop

Cause — The app crashes immediately on start (a syntax error, a missing env var, a port already in use), so PM2 keeps restarting it. The restart count (↺ column) climbs rapidly.

Solution — Read the logs to find the real error, then cap the restarts and add a backoff while you fix it:

pm2 logs api --lines 100
pm2 start api.js --max-restarts 5 --exp-backoff-restart-delay 200

Prevention — Set min_uptime and max_restarts in your ecosystem file so a broken deploy fails loudly instead of looping forever.


Problem: pm2 reload causes downtime

Cause — reload only does a true zero-downtime rolling restart in cluster mode. A fork-mode app falls back to a plain restart.

Solution — Start the app in cluster mode so reload becomes rolling:

pm2 start api.js -i max
pm2 reload api

Prevention — Use exec_mode: 'cluster' and instances in your ecosystem file for any HTTP service that needs zero-downtime deploys.


Problem: Reloaded app drops connections even in cluster mode

Cause — PM2 considers a new worker ready on its listening event, but your app needs more setup time before it can serve traffic, so the old worker is killed too early.

Solution — Opt into the explicit ready signal and raise the timeout:

pm2 start api.js -i 4 --wait-ready --listen-timeout 10000
// signal readiness only when truly ready
process.send('ready');

Prevention — Set wait_ready: true and a generous listen_timeout in the ecosystem file.


Problem: My apps did not come back after a server reboot

Cause — Either the startup hook was never installed, or the process list was never saved.

Solution — Do both, in order:

pm2 startup            # then run the sudo command it prints
pm2 start ...          # start your apps
pm2 save               # freeze the list

Prevention — Re-run pm2 save every time you change which apps are running.


Problem: PM2 commands behave strangely after an upgrade

Cause — The npm package was upgraded but the in-memory daemon is still the old version. PM2 prints a >>>> In-memory PM2 is out-of-date warning when this happens.

Solution —

pm2 update

Prevention — Run pm2 update immediately after every npm install pm2@latest -g.


Problem: Logs have filled the disk

Cause — PM2's built-in log files grow without bound.

Solution — Flush now and install rotation:

pm2 flush
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M

Prevention — Install pm2-logrotate as part of every server's standard setup.


Problem: Cannot send a line to a process / pm2 send does nothing

Cause — pm2 send and pm2 attach only work for fork-mode processes. Cluster-mode processes have no single shared stdin.

Solution — Start the target app in fork mode (omit -i) if you need to interact with its stdin.

Prevention — Reserve stdin-driven interaction for fork-mode apps.


Problem: PM2 will not start on a Bun-only system

Cause — Either Bun is older than 1.1.25, or there is no node binary for PM2's shebang to resolve.

Solution — Upgrade Bun, and symlink node to bun:

sudo ln -s $(which bun) /usr/local/bin/node

Prevention — Keep Bun at 1.1.25+ on production hosts.


25. Frequently Asked Questions

Q: Does PM2 only work with Node.js? No. PM2 manages Python, Ruby, bash, and any binary via --interpreter (or --interpreter none for a raw executable). Node.js just gets extra features like cluster mode.

Q: What is the difference between restart and reload? restart kills and re-spawns the process, causing brief downtime. reload performs a one-at-a-time rolling restart with zero downtime, but only in cluster mode.

Q: What is the difference between stop and delete? stop halts the process but keeps it in PM2's list so you can start it again. delete removes it from the list entirely.

Q: Does the daemon keep running after I close my terminal? Yes. That is the whole point — the PM2 daemon is detached and keeps your apps running independently of any shell.

Q: How do I make my apps survive a reboot? Run pm2 startup once (and the sudo command it prints), then pm2 save after your apps are running.

Q: How many instances should I run in cluster mode? pm2 start app.js -i max uses one instance per CPU core, which is a good default for CPU-bound HTTP servers. Use -i -1 to leave one core for the OS.

Q: Where are my logs? In ~/.pm2/logs/ by default, one -out.log and one -error.log per app (or per instance unless you use --merge-logs). Stream them with pm2 logs.

Q: How do I pass environment variables? Put them in the env block of an ecosystem file, and use named blocks (env_production) selected with --env production. Remember to add --update-env on restart to apply changes.

Q: Why didn't my environment variable change take effect on restart? By design, restart/reload keep the original environment. Add -a / --update-env to refresh it.

Q: Can I run multiple independent PM2 instances on one machine? Yes. Set a different PM2_HOME for each — they get separate daemons, sockets, and process lists.

Q: How do I update PM2 without losing my running apps? npm install pm2@latest -g then pm2 update. PM2 saves, restarts the daemon, and restores your apps.

Q: How do I report a bug? Run pm2 report and attach its output to an issue at the PM2 GitHub repository.

Q: Do I need a PM2+ account? No. PM2+ is an optional hosted dashboard. Every feature in this guide works without it.