esedark
engineer reviewing linux services and deployment status on multiple screens

pm2 / supervisor / systemd / node.js / laravel

PM2 vs Supervisor vs systemd for Node.js and Laravel

Choosing a process manager is not about taste. It affects restart behaviour, deploy safety, log visibility, worker recovery and how much hidden operational debt your stack accumulates.

If you are comparing PM2 vs Supervisor vs systemd for Node.js and Laravel, start with one simple rule: choose the smallest tool that gives you reliable restarts, clear ownership and useful logs. The wrong process manager does not usually fail loudly. It creates quiet instability that appears later as duplicate jobs, missing workers or random post-deploy downtime.

This matters even more when your application already depends on queues, schedulers, APIs and web services that must keep behaving predictably. It is the same operational discipline behind clean Nginx boundaries for Laravel and sane infrastructure isolation: fewer mysteries, clearer recovery.

What each tool is really for

All three tools can keep a process alive. That does not mean they solve the same problem.

  • PM2 is convenient for Node.js apps, clusters, env handling and quick operational dashboards.
  • Supervisor is a generic process monitor that works across languages and is simple to understand.
  • systemd is the native Linux service manager and usually the cleanest choice for long-lived production services.

The practical question is not which one can restart a process. The practical question is which one matches your deployment model, logging path and failure boundaries.

My default decision rule

For most production Linux servers, systemd should be the default starting point. It is already part of the operating system, it integrates naturally with boot, permissions and journaling, and it reduces one extra layer of tooling.

PM2 makes sense when the workload is strongly Node.js-centric and the team benefits from its ecosystem features. Supervisor still fits mixed setups or older operational patterns, but I would not add it by default to a new server if systemd already covers the need cleanly.

Typical use cases by stack

Node.js API
  -> systemd by default
  -> PM2 if cluster mode and Node-focused operations help

Laravel queue worker
  -> systemd by default
  -> Supervisor if team already runs Laravel workers that way and it is documented

Mixed host with utility scripts
  -> systemd for core services
  -> avoid stacking multiple managers unless there is a real reason

That last line matters. When one server runs PM2 for Node.js, Supervisor for queues and systemd for everything else, operational ownership gets muddy fast.

Common mistakes

The first mistake is layering tools without a reason. Running PM2 inside a service already managed by systemd can work, but it often hides who is actually responsible for restarts and shutdown order.

The second mistake is treating restart loops as health checks. A process that keeps auto-restarting may look alive while still failing the actual business job.

The third mistake is sending logs everywhere. If stdout goes one place, Laravel logs another and queue failures a third, incident response slows down immediately.

The fourth mistake is ignoring deploy semantics. A worker restart strategy that is acceptable for a stateless Node.js API may be wrong for long-running Laravel queue jobs.

The fifth mistake is forgetting compliance and traceability. If logs include request metadata, user identifiers or public-data processing evidence, retention and access rules must be explicit. Operational convenience is not a reason to create an audit blind spot.

Practical checklist before choosing

  • define whether the process is stateless, queued or long-running
  • decide where stdout, stderr and app-level logs will live
  • document who restarts the service during deploys
  • set backoff or restart limits to avoid noisy crash loops
  • separate web processes from queue workers clearly
  • store environment variables in one controlled path
  • record which services touch client or public data
  • test boot, restart and failure recovery on a real server
  • keep one clear owner per process group
  • avoid double supervision unless the reason is explicit

Examples that stay readable

A clean systemd unit for a Node.js API is often enough.

[Unit]
Description=Node API
After=network.target

[Service]
WorkingDirectory=/var/www/api/current
ExecStart=/usr/bin/node server.js
Restart=on-failure
User=www-data
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

A documented Supervisor config for Laravel workers can also be fine if the team already operates it well.

[program:laravel-worker]
command=php /var/www/app/current/artisan queue:work --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)02d
numprocs=2
autostart=true
autorestart=true
stdout_logfile=/var/log/laravel-worker.log
stopwaitsecs=3600

The point is not the syntax. The point is that restart rules, stop behaviour and log destinations should be obvious.

How this affects stability

Stability is not just uptime. Stability means a deploy does not kill the wrong workers, a reboot brings back the correct services, and a failure can be traced to one service definition instead of three overlapping tools.

This is also where monitoring becomes non-negotiable. If the service manager says "running" but queue depth, error rate or job age says otherwise, you still have an incident. That is why this decision ties directly into logs, alerts and monitoring basics and into access discipline such as safe client SSH access.

When hiring a technical person makes sense

If your team is already dealing with duplicate jobs, random worker exits, unclear restarts after deploys or servers where nobody knows whether PM2, Supervisor or systemd is in charge, the issue is no longer a syntax question. It is operational ownership.

That is where technical services or direct support through fractional CTO work can help. The useful work is mapping processes, simplifying supervision, tightening log flow and deciding what should be explicit before the next outage makes the decision for you.

Final takeaway

Use systemd by default when Linux already gives you the right primitives. Use PM2 when Node.js-specific tooling clearly improves operations. Keep Supervisor when it is already working cleanly and documented, not because it is familiar.

If you need help untangling a host that runs Node.js, Laravel and background workers with unclear restart logic, use contact and include the current process map, deploy flow and where failures usually appear. That is enough to simplify the stack quickly.