PM2 stores per-application logs in ~/.pm2/logs/, with <app-name>-out.log for stdout and <app-name>-error.log for stderr. The PM2 daemon's own log is ~/.pm2/pm2.log. The ~ is the home directory of the user that started the PM2 daemon — so apps managed under sudo/root live in /root/.pm2/logs/, not your user's home. Run pm2 info <app> to print the exact paths for any process.
Quick Reference: PM2 Log File Paths
| Item | Path |
|---|---|
| Per-app stdout | ~/.pm2/logs/<app-name>-out.log |
| Per-app stderr | ~/.pm2/logs/<app-name>-error.log |
| PM2 daemon log | ~/.pm2/pm2.log |
| PM2 home directory | ~/.pm2/ (override with $PM2_HOME) |
| Process metadata | ~/.pm2/dump.pm2 |
| PID file | ~/.pm2/pm2.pid |
| Root-managed app logs | /root/.pm2/logs/<app-name>-out.log |
| Custom paths | out_file / error_file in ecosystem.config.js |
If an app runs as multiple instances in cluster mode, PM2 appends the instance id, e.g. api-out-0.log, api-out-1.log, unless merge_logs: true is set.
How to View and Tail PM2 Logs
pm2 logs # tail all apps, live
pm2 logs <app-name> # one app
pm2 logs <app-name> --lines 200 # show 200 lines of backlog first
pm2 logs --err # only stderr across all apps
pm2 logs --out # only stdout
pm2 logs --raw # no PM2 prefix/timestamps
pm2 logs --timestamp # add timestamps
pm2 info <app-name> # prints exact "out log path" / "error log path"
pm2 describe <app-name> # same info, verbose
You can also read the files directly once you know the path:
tail -f ~/.pm2/logs/api-out.log
tail -f ~/.pm2/logs/api-error.log
sudo tail -f /root/.pm2/logs/api-error.log # root-managed app
The web dashboard pm2 monit shows a live tail alongside CPU/memory per process.
Configuring Log Paths in the Ecosystem File
The clean way to control logging is the ecosystem.config.js file:
module.exports = {
apps: [{
name: "api",
script: "./server.js",
out_file: "/var/log/myapp/api-out.log",
error_file: "/var/log/myapp/api-error.log",
log_file: "/var/log/myapp/api-combined.log", // merged out+err
merge_logs: true, // single file across cluster instances
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
time: true // prefix each line with a timestamp
}]
};
Apply changes:
pm2 restart ecosystem.config.js --update-env
Useful per-app options:
out_file/error_file— explicit paths (use/dev/nullto discard).log_file— a combined file that receives both streams.merge_logs: true— one set of files for all cluster instances instead of per-instance numbered files.log_date_format— timestamp format PM2 prepends to each line.
Log Rotation
PM2 does not rotate logs by itself — files grow unbounded until you flush or rotate them.
Clear logs manually:
pm2 flush # empty all log files
pm2 flush <app-name> # empty one app's logs
For automatic rotation, install the official module:
pm2 install pm2-logrotate
Then tune it:
pm2 set pm2-logrotate:max_size 10M # rotate at 10 MB
pm2 set pm2-logrotate:retain 7 # keep 7 rotated files
pm2 set pm2-logrotate:compress true # gzip old files
pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # also rotate daily at midnight
Rotated files appear next to the originals with a timestamp suffix, e.g. api-out__2026-06-01_00-00-00.log. Alternatively you can manage PM2's files with system logrotate and the copytruncate directive, but the module is the supported path.
Common Errors You'll Find in PM2 Logs
Error: listen EADDRINUSE: address already in use :::3000— another process (often a stale PM2 instance) holds the port; find it withlsof -i :3000and stop the duplicate.Error: Cannot find module 'express'— dependencies weren't installed in the app's directory; runnpm installandpm2 restart <app>.App [api:0] exited with code [1] via signal [SIGINT]— the process crashed or was killed; the real stack trace is in the-error.logjust above this PM2 line.script exited too quickly, PM2 will restart it/reached max restart limit— the app keeps crashing on startup; check the error log and considermax_restarts/min_uptime.UnhandledPromiseRejectionWarningor an unhandled exception stack — application-level bug written to the error log; PM2 records it but doesn't interpret it.PM2 error: Cannot read property ... of undefinedinpm2.log— a daemon-side issue; trypm2 updateto reload the in-memory daemon after a PM2 version change.
Troubleshooting: Logs Missing or Empty
- Can't find the logs at all — They're under the home of whoever started the daemon. If you used
sudo pm2 start, look in/root/.pm2/logs/. Confirm withpm2 info <app>. pm2 logsshows nothing — The app may be logging to a customout_file/error_file, or it writes via a logging library to its own file instead of stdout/stderr. Checkpm2 describe <app>for the configured paths.- Logs stopped updating — PM2 may be holding an old file handle after an external rotation (e.g. system logrotate without
copytruncate). Runpm2 reloadLogsto reopen the files. - Empty error log but the app is crashing — Errors may be going to stdout instead of stderr, so check
-out.logtoo, or setmerge_logs: trueto see everything in one place. - Logs reset after reboot but app didn't restart — You didn't persist the process list. Run
pm2 saveand set up the startup hook withpm2 startupso apps (and logging) resume on boot. - Disk filling from huge log files — PM2 has no built-in cap; install
pm2-logrotateand setmax_size/retain, or schedulepm2 flush.