PM2
Keep PM2
You deploy Node and need cluster mode across cores, restart-on-crash with backoff, boot persistence, and zero-downtime reload.
PM2 is a production supervisor that also watches files in dev. lpm is the Mac workspace around your local stack: one pane per service, a switcher across repos, and copies for parallel agents.
If both columns describe you, that is the normal case — run both.
The short answer
Yes. pm2-dev and --watch restart your app on file change, and if PM2 already runs production, one config for both is a real reason to stay.
What PM2 does not give you locally is a pane per service you can read and search, a switcher across projects, or a second copy of the stack for a parallel agent. It is a supervisor, not a workspace. lpm is the workspace, and it is additive: it supervises nothing in production and it never wraps PM2. Keep ecosystem.config.js for the server; for the laptop, declare those same services to lpm — kept to yourself in your own project file, or committed as a .lpm.yml so a teammate gets the same set.
pm2 start ecosystem.config.js --only "web,api"
lpm start myapp --profile devPM2
You deploy Node and need cluster mode across cores, restart-on-crash with backoff, boot persistence, and zero-downtime reload.
lpm
You want every service in its own live pane, a switcher across projects, and copies of the stack for parallel agents.
Both
ecosystem.config.js on the server, .lpm.yml on the laptop. They never nest and they never fight.
The reason people reach for PM2 locally is that a dev server tied to a terminal window dies with the window. lpm's services do not run in the app — they run outside it, so quitting lpm is not pm2 stop. Relaunch and every pane is still there, still labelled, still streaming.
no equivalent to pm2 startup and pm2 save; you start the project again
the service stays down; its pane keeps the last output
with backoff
Two of those three go to PM2. That is the honest shape of this comparison — lpm is built for the loop you are in, not the box you left running.
Facts checked . The six rows PM2 wins are cited individually, because they are the reason to keep it. lpm's own rows were re-checked against the app source the same day.
Six of these rows go to PM2. Each one is a production problem — cluster mode, crash recovery, boot persistence — rather than a local-dev one.
| Capability | lpm | PM2 |
|---|---|---|
| Services keep running after you close the app | Yes | Yes |
| Every service in its own live pane instead of one log stream | Yes | pm2 logs |
| Switch between projects visually | Yes | No |
| Checks declared ports before starting and names the holder | ask, free, or fail | No |
| Declares service start order | dependsOn | No |
| Named service subsets | profiles | --only |
| Wait for a port or a service from a script | lpm wait --port 3000 | No |
| Copy the whole stack for a second agent | up to 50 worktrees or standalone copies | No |
| Runs Claude Code and Codex in panes beside the services | Yes | No |
| Runs Node, Python, shell commands and binaries | Yes | Yes |
| Cluster mode across CPU cores with load balancing | No | Yes |
| Auto-restart on crash with backoff and memory limits | stays down; the pane keeps its last output | Yes |
| Comes back after a reboot (pm2 startup / pm2 save) | No | Yes |
| Zero-downtime reload on deploy | No | Yes |
| Log files and rotation | live scrollback only | pm2-logrotate |
| CPU and memory dashboard | No | pm2 monit, PM2 Plus |
| Scriptable from a shell, with JSON for the caller | lpm CLI, --json on nearly every verb | pm2 CLI |
There is no logs directory. lpm logs api --lines 500 reads that service pane's scrollback, so what you get back is always current — and when the pane goes, the history goes with it. For output you can still read next week, PM2's log files plus pm2-logrotate remain the right tool.
The verbs line up almost one to one. Two of them have no lpm equivalent, and three lpm verbs have no pm2 original.
| pm2 | lpm | Notes |
|---|---|---|
pm2 start ecosystem.config.js | lpm start myapp | |
pm2 start … --only web | lpm start myapp --profile dev | |
pm2 list | lpm list | |
pm2 show web | lpm project myapp | |
pm2 logs web --lines 200 | lpm logs web --lines 200 | |
pm2 restart web | lpm service web restart | |
pm2 stop all | lpm stop myapp | |
pm2 monit | no equivalent | lpm shows panes, not resource graphs |
pm2 startup / pm2 save | no equivalent | |
— | lpm wait --port 3000 --timeout 60 | hold a script until the port is listening |
— | lpm duplicate myapp -n 3 --run claude --prompt "…" | three copies, each running its own agent |
— | lpm worktree myapp -n 3 | three linked Git worktrees instead — untracked files like .env and node_modules stay behind |
pm2
pm2 start ecosystem.config.jslpm
lpm start myapppm2
pm2 start … --only weblpm
lpm start myapp --profile devpm2
pm2 listlpm
lpm listpm2
pm2 show weblpm
lpm project myapppm2
pm2 logs web --lines 200lpm
lpm logs web --lines 200pm2
pm2 restart weblpm
lpm service web restartpm2
pm2 stop alllpm
lpm stop myapppm2
pm2 monitlpm
no equivalentlpm shows panes, not resource graphs
pm2
pm2 startup / pm2 savelpm
no equivalentpm2
—lpm
lpm wait --port 3000 --timeout 60hold a script until the port is listening
pm2
—lpm
lpm duplicate myapp -n 3 --run claude --prompt "…"three copies, each running its own agent
pm2
—lpm
lpm worktree myapp -n 3three linked Git worktrees instead — untracked files like .env and node_modules stay behind
lpm start and lpm stop, and any lpm service web restart, need the app up: the panes belong to it, so a shell with lpm quit gets “lpm app is not running” instead. Reading is looser — lpm logs, lpm list and lpm wait --port inspect the services themselves. The exception on that side is lpm status: agent status is the app's to report, so it says there is no live status until lpm is up again. Every row above is also a line an agent can run for you.
The same two services, declared twice. Nothing here replaces the ecosystem file — it stays on the server.
module.exports = {
apps: [
{ name: "web", script: "npm", args: "run dev" },
{ name: "api", script: "./bin/api", env: { PORT: 4000 } },
],
};services:
web: npm run dev
api:
cmd: ./bin/api
port: 4000
env:
PORT: "4000"
dependsOn: [web]
profiles:
dev: [web, api]apps[] entry's name plus script/args becomes one services: key and its command — a service with no options is one line.dependsOn sets start order, which ecosystem.config.js has no field for. It orders starts; it does not wait for readiness — that is lpm wait --port.port: is what lpm checks for conflicts and what lpm wait watches. The port your service actually binds still comes from your command or env:.Each field on the right — cmd, port, env, dependsOn and profiles — has its own entry in the config reference.
The same verbs above, called by Claude Code — a fresh tab opens in lpm with the output.
Both run multiple processes. PM2 is strongest as a supervisor and also offers local watch mode; lpm specializes in an interactive multi-project Mac workspace. And if both columns describe you, that is the normal case.
A short video: duplicate a project so each agent has its own copy.Click anything — each repo runs live in your browser.
lpm is a macOS app with a multi-pane terminal workspace. Open this page on your computer to try the interactive demo.
Get lpm for MacOr check your Macs from your iPhoneClick a step to run it in the window.
Done poking around? Get lpm for Mac and point it at your own projects.
pm2 startup equivalent, so you start the project again.pm2-runtime start ecosystem.config.js runs in a pane like anything else. Most people do not, because you would then have two things deciding whether a process is alive. Point lpm at the same commands your ecosystem file runs and skip the layer.If PM2 and tmux are both in your setup: what changes when the tool you are replacing keeps panes alive rather than processes.
When the things you are starting are images rather than npm scripts, and what a container stack costs on a laptop.
services, port, env, dependsOn and profiles — every field a service can take, with worked examples.
How Claude Code and Codex call the CLI: start a project, wait for a port, read a pane, queue the next command.
The tab beside your services: status on the tab while an agent works, and a diff to review before you keep it.
Linked worktrees for parallel agents, and the .env and node_modules a fresh checkout does not bring.
MIT-licensed, free, no account. PM2 stays where it belongs — on the server. lpm takes the laptop: a pane per service, a switcher across projects, and copies of the stack for Claude Code and Codex.Not installing today? Drop the .lpm.yml above into the repo, beside your ecosystem.config.js. Point lpm at that folder whenever you get to it — the services are already declared, and anything lpm also detects there is yours to prune.