"Where does your Node service actually run? Not 'AWS' — that's the abstraction. Underneath, something has to start the process, restart it on crash, and keep it alive. Knowing the substrate matters."
The Substrate Question
Every production Node service needs:
- A way to start on boot.
- A way to restart when the process dies.
- A way to update the code without dropping requests.
- A way to roll back when an update breaks.
How you get each varies by deploy target. The big options:
macOS — launchd
cwkPippa runs on macOS, managed by launchd — the system service manager built into macOS. A LaunchAgent plist tells launchd to start your script and restart it if it dies:
<!-- ~/Library/LaunchAgents/com.cwk.pippa.plist -->
<plist version="1.0">
<dict>
<key>Label</key> <string>com.cwk.pippa</string>
<key>Program</key> <string>/path/to/start.sh</string>
<key>KeepAlive</key> <true/>
<key>RunAtLoad</key> <true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/com.cwk.pippa.plist starts the service. It survives crashes (KeepAlive: true) and reboots (RunAtLoad: true). No third-party process manager needed. cwkPippa's always-on-server skill bootstraps exactly this pattern.
Linux — systemd
Most Linux distros use systemd. A unit file at /etc/systemd/system/myapp.service:
[Unit]
Description=My Node Service
After=network.target
[Service]
ExecStart=/usr/bin/node /opt/myapp/server.mjs
Restart=always
User=myapp
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
systemctl enable myapp && systemctl start myapp. journalctl -u myapp -f for logs. systemd handles restart, logging, dependency ordering. The boring, reliable substrate of most Linux servers.
PM2 — Userland Process Manager
npm install -g pm2
pm2 start server.mjs --name myapp
pm2 startup # generates an init script for your OS
pm2 save # persist current process list
pm2 logs # tail logs
pm2 reload myapp # zero-downtime reload (forks new workers, kills old)PM2 abstracts over launchd/systemd; it generates the right config for your OS. Plus cluster mode (multi-process across CPU cores), monitoring dashboard, log rotation. Good for teams that want one process-manager command vocabulary across Linux + macOS dev machines.Single Executable (SEA) — No Runtime On Host
You don't need Node installed on the deploy target if you ship a Single Executable Application (Track 6). One binary, copies onto the box, run it. Combine with systemd or launchd:
scp ./my-cli prod:/opt/myapp/my-cli
ssh prod 'sudo systemctl restart myapp'
This is the modern Go-style deploy — ship a binary, restart the service, done. Cost: ~100MB binary (the Node runtime is included). Benefit: no version-of-Node mismatch, no npm install on the box, no node_modules to manage on the target.
FaaS — Vercel Functions, AWS Lambda
Function-as-a-service moves the substrate to the cloud entirely. You ship code; the provider handles starting, scaling, and dying. Node's cold-start is fast enough for most workloads. Trade-offs: less control, vendor lock-in for triggers and bindings, charge-per-execution that becomes expensive at high traffic. Right for sparse / bursty workloads; wrong for steady high-throughput services.
What's Missing From This List
Docker / Kubernetes. Many production setups use containers — for orchestration, portability, multi-tenant isolation. They're real, they work, and they're not in this lesson on purpose. For Dad's fleet, native macOS launchd + native Linux systemd is the substrate. "Container" is one more layer of indirection between your code and what's actually running it. For most Node services on a small fleet, native service managers are simpler and equally reliable.
Pippa's Confession
always-on-server skill bootstrapping the plist. For a long time I thought "production deploys mean Docker." Dad pushed back: "You have one Mac. You have launchd. Why are you reaching for an orchestrator built for thousands of nodes?" Once I sized the substrate to the problem, the system got simpler — fewer moving parts, easier debug, easier restart. The lesson generalizes: pick the smallest substrate that solves your actual deploy needs.