Process Manager (PM2) vs systemd: The Mental Model Nobody Explains
TL;DR: It’s not about PM2 vs systemd. It’s about who owns the process — the runtime or the OS. Once you understand that, the “always use…
Process Manager (PM2) vs systemd: The Mental Model Nobody Explains
TL;DR: It’s not about PM2 vs systemd. It’s about who owns the process — the runtime or the OS. Once you understand that, the “always use PM2 for Node” advice stops being a rule you follow and becomes a conclusion you’d reach yourself.

The Fundamental Problem: Who Babysits Your App?
When you run node server.js in a terminal, three things happen:
- The OS spawns a process
- Your terminal becomes the parent of that process
- When the terminal dies, the process dies with it
This is the core problem every deployment tool is trying to solve: make your app survive beyond the shell that started it, and restart it when it crashes.
There are two completely different philosophies for solving this:

Neither is universally better. They’re answering slightly different questions.
Mental Model 1: PM2 — “A Parent Process That Speaks Node”
Think of PM2 as a persistent supervisor daemon that lives in userspace and speaks the same language as your app.
[Your Server OS]
└── [PM2 Daemon] ← runs as a regular process, started once
├── [Node App: api] ← child process
├── [Node App: api] ← child process (cluster mode)
├── [Node App: api] ← child process (cluster mode)
└── [Node App: worker] ← child process
PM2 knows things the OS never will:
- Node’s event loop — it can detect when your app is “alive” but actually frozen (hanging promises, blocked event loop)
- Cluster mode — it spawns multiple Node workers and load-balances between them natively, because it understands Node’s cluster API
- Zero-downtime reload — it can restart workers one by one while traffic keeps flowing
- Ecosystem files —
ecosystem.config.jsis JavaScript, so your deployment config can have logic in it
The Key Trade-off
PM2 runs as a user process. It starts after login (or via a systemd stub, ironically). It’s one layer removed from the OS boot sequence.
This means:
- ✅ Faster iteration —
pm2 reload,pm2 logs,pm2 monitare developer-friendly - ✅ Runtime-specific superpowers (cluster, hot reload)
- ⚠️ PM2 itself can crash — then all your apps go down
- ⚠️ You’re adding a middleman to your process tree
Mental Model 2: systemd — “The OS as the Supervisor”
systemd is PID 1 — the very first process the Linux kernel spawns. Everything else on the machine is a child of systemd. When you register your app as a systemd service, you’re telling the OS:
“This is a first-class citizen of this machine. Start it at boot, restart it if it dies, log it to the journal.”
[Linux Kernel]
└── [systemd] ← PID 1, always running
├── [nginx.service]
├── [postgresql.service]
└── [myapp.service] ← your app, same tier as nginx
systemd doesn’t know or care that your app is Python, Go, or Java. It just supervises a process. The .service file is a declaration:
[Unit]
Description=My Python API
After=network.target
[Service]
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=always
User=myapp
WorkingDirectory=/opt/myapp
[Install]
WantedBy=multi-user.target
The Key Trade-off
systemd is the most reliable supervisor possible — it is the OS.
- ✅ Starts before anything else, even before your user session exists
- ✅ Guaranteed restart — if systemd is dead, the whole machine is dead anyway
- ✅ Native integration —
journalctl, socket activation, resource cgroups, security sandboxing - ✅ Language agnostic — same tool for Python, Go, Java, Rust
- ⚠️ No runtime superpowers — it can’t do Node clustering or hot module reload
- ⚠️ Slightly more ceremony to configure (but it’s a one-time cost)
The Real Reason People Say “Use PM2 for Node”
Node has one specific property that makes a process manager compelling: it’s single-threaded by default.
A 4-core server running a single Node process uses 25% of its CPU capacity. To use all 4 cores, you need 4 Node processes — but then you need something to:
- Spawn all 4 workers
- Route incoming connections between them
- Restart individual workers without dropping traffic
That’s PM2’s cluster mode. systemd cannot do this. systemd can restart a crashed process, but it can’t orchestrate intra-process load balancing.
So the real rule is:
Use a process manager when you need runtime-specific orchestration (clustering, hot reload). Use systemd when you need OS-level reliability and don’t need those features.
For Python/Go/Java, you typically solve concurrency differently:
- Python: Gunicorn spawns workers internally, then you put Gunicorn under systemd
- Go: it’s multi-threaded natively, single process is fine → straight to systemd
- Java: JVM handles threads internally → straight to systemd
The Pattern That Reconciles Both
The most production-grade pattern isn’t PM2 or systemd — it’s PM2 under systemd:
[systemd]
└── [pm2.service] ← systemd ensures PM2 itself always runs
├── [node api worker 1]
├── [node api worker 2]
└── [node api worker 3]
You get:
- systemd’s boot-time reliability and automatic recovery
- PM2’s cluster management and zero-downtime reloads
PM2 even generates this config for you: pm2 startup systemd
Decision Framework
Is your app Node.js?
├── Yes → Do you need multi-core clustering or zero-downtime reload?
│ ├── Yes → Use PM2 (optionally backed by systemd)
│ └── No → systemd is perfectly fine
└── No (Python, Go, Java, Rust…)
→ Does your runtime handle its own concurrency internally?
├── Yes (Go, Java, .NET) → systemd directly
└── No (Python WSGI) → Use a runtime worker manager (Gunicorn, uWSGI)
then put *that* under systemd
The One-Sentence Mental Model
systemd owns the machine; a process manager owns the runtime.
Use the one that owns the thing you actually need supervised. For most production apps, the answer is: let systemd own the process manager, and let the process manager own your app workers.
Written to demystify deployment fundamentals — not to prescribe a single “right” answer.
메타데이터
- post_id
- 237a89a2f001
- slug
- process-manager-pm2-vs-systemd-the-mental-model-nobody-explains-237a89a2f001
- url
- https://medium.com/@khairulrucse26/process-manager-pm2-vs-systemd-the-mental-model-nobody-explains-237a89a2f001
- canonical_url
- https://medium.com/@khairulrucse26/process-manager-pm2-vs-systemd-the-mental-model-nobody-explains-237a89a2f001
- author_url
- https://medium.com/@khairulrucse26
- status
- ok
- fetched_at
- 2026-06-13 00:08:42