Every command accepts a target: a numeric id (0), a process name (my-api), a namespace (my-namespace), or all. A target that matches a process name (or its cluster instances) always wins; otherwise a namespace target operates on every process in the group. Unknown targets are clear errors — Process or namespace "x" not found — nothing to <verb> — instead of a silent no-op.
Namespaces#
A namespace is a first-class grouping mechanism, not just metadata. Assign one at start, and every lifecycle verb accepts it as a target:
pboss start ./web.ts --name web --namespace my-app
pboss start ./api.ts --name api --namespace my-app
pboss start ./worker.ts --name worker --namespace my-app
pboss restart my-app # the whole group, in one command
pboss stop my-app # ✓ Stopped 3 processes in namespace "my-app"
pboss start my-app # resume every stopped member — atomically
pboss delete my-app # confirmed first — or --force to skip
Group operations report what they touched (a one-line summary above the process table), and the auto-saved dump follows immediately, so the group state survives reboots by default. pboss list shows the namespace column.
Atomic startup (#31)#
A namespace is one lifecycle group, so starting it is atomic. If any member fails to start, the members that start invocation brought up are rolled back — stopped, best-effort, in reverse start order. The original failure stays the primary error; rollback results are reported separately:
namespace "my-app" startup failed: Script not found: ./worker.ts
Rollback: ✓ api stopped, ✓ web stopped
The rollback boundary is strictly invocation-scoped:
- Members that were already running are never rolled back — only what the operation itself started.
- A namespace failure never touches other namespaces or standalone (namespace-less) processes.
pboss start allapplies the same boundaries: standalone processes start independently, every namespace resumes atomically as one unit.- Namespace
restartis stop-all + atomic start with the same rollback contract. Namespacestop/reload/deleteare best-effort across members — one stubborn member does not leave the rest of the group mid-operation. - Same-namespace operations are serialized — two terminals cannot interleave a
restartand astopon one group. Different namespaces stay independent.
Standalone behavior is unchanged: a process without a namespace is fully independent, and a failing standalone app never rolls back or blocks the others in an ecosystem start.
Member-exit policy: onNsMemberExit#
A namespaced process can decide what to do when another member of its namespace exits for good — a terminal stop, or a crash after the restart budget is exhausted. Not a pboss-initiated stop, and not a crash that auto-restart is already handling:
ignore(default) — do nothing. Each member keeps running on its own.exit— stop this process too, so the namespace either runs complete or not at all.
pboss start ./web.ts --name web --namespace my-app --on-ns-member-exit exit
// ecosystem.config.js
module.exports = {
apps: [
{ name: "web", script: "./web.ts", namespace: "my-app", onNsMemberExit: "exit" },
{ name: "api", script: "./api.ts", namespace: "my-app", onNsMemberExit: "exit" },
],
};
The policy is per-app and only applies to processes with a namespace — standalone processes are never affected by another process’s exit. pboss-initiated stops (user stop, rollback, the policy itself) never trigger the policy again, so it cannot cascade. The setting persists in the process dump and survives daemon restarts.
Dependencies (#33)#
Any process can declare what it needs before it can start. pboss resolves the whole dependency graph, starts what it owns in the right order, and checks what the operating system owns:
// ecosystem.config.js
module.exports = {
apps: [
{ name: "postgres", script: "./postgres-wrapper.ts" },
{ name: "api", script: "./api.ts", dependsOn: ["postgres", "redis"] },
{ name: "worker", script: "./worker.ts", dependsOn: ["api"] },
],
};
pboss start worker # starts postgres → api → worker, in that order
pboss start api.ts --name api --depends-on postgres,redis # CLI form
Resolution order: a dependency name resolves against pboss processes first (exact names and cluster instances). If nothing matches, pboss asks the system service manager — on Linux, systemd. postgresql maps to postgresql.service, mongodb to mongod.service, redis to redis.service, with common alias differences covered. Only an active unit satisfies a dependency.
pboss never starts, stops, or otherwise manages a system service — the check is read-only. Services owned by systemd, another admin, or another orchestrator stay theirs.
Policies#
Every dependency is "required" (default — the dependent cannot start until it is satisfied) or "optional" (preferred, never blocks):
dependsOn: ["postgres", { name: "metrics", policy: "optional" }]
The CLI flag accepts name or name:optional entries, comma-separated: --depends-on postgres,metrics:optional.
Start and restart semantics#
- Already-running dependencies are never restarted —
pboss start api(orrestart api) leaves a runningpostgresalone. - Resolution is recursive: starting
workerpulls upapi, which pulls uppostgres. Independent dependencies start concurrently — the graph is level-ordered, not a flat chain. - Cycles (
a → b → a, or a self-reference) are detected before anything starts — a clear error, never an infinite loop. - Rollback is invocation-scoped, same contract as namespaces: if
apifails, dependencies this start brought up are stopped again; processes already running are preserved. restartpre-flights dependencies before stopping the process — a blocked restart fails while the process is still running, instead of stopping it and failing to bring it back.- Restarting a dependency never restarts its dependents (runtime propagation is a future policy, not a surprise).
- Dependencies can cross namespace boundaries —
webin namespacefrontendmay depend onapiin namespacebackend.
dependsOn persists with the process configuration. Boot recovery brings the fleet up dependencies-first regardless of the dump’s save order, and one failed graph never blocks unrelated graphs.
Blocked starts say exactly why#
Cannot start "api".
Required dependency "postgresql" is unavailable.
Provider: systemd
Service: postgresql.service
State: inactive
A name that resolves nowhere reports both misses — Checked: ProcBoss applications: not found / System services: not found — and API clients get the same facts as a structured dependencyFailure object (see the programmatic API).
pboss start#
Start a new process or processes.
pboss start server.ts
pboss start <name|namespace> — when the positional is not an existing script or config file — resumes processes that already exist: every stopped member comes back online, online ones are untouched, nothing new is created. Resuming a namespace is atomic — if any member fails to start, only the members this invocation started are rolled back.
pboss start my-app # resume every stopped process in the namespace — atomically
pboss start api # resume one stopped process by name
pboss start server.ts --name api -- --port 8080 --host 0.0.0.0
pboss start server.ts --name api --env NODE_ENV=production --env API_KEY=xxx
pboss start server.ts --name api --max-memory-restart 512M
pboss start server.ts --interpreter "deno run -A" --name deno-api
pboss start server.ts --name api --wait-ready --listen-timeout 10000
Arguments after -- are passed through to your script. The same set of options is available in ecosystem files and the configuration reference.
Options#
| Flag | Description | Default |
|---|---|---|
--name <name> | Process name | Script filename |
--instances <n> | Number of instances. Use max for all CPUs | 1 |
--exec-mode <mode> | fork or cluster | fork |
--cwd <path> | Working directory | Current directory |
--env <KEY=VAL> | Environment variable (repeatable) | — |
--interpreter <bin> | Custom interpreter binary | Auto-detected |
--interpreter-args <args> | Arguments for the interpreter | — |
--permissions, --perms <list> | Deno only (runtime-unique — ignored under Bun/Node): comma-separated permission list, e.g. allow-read,allow-net=api.com,deny-write; all = -A, none = no permissions | — |
--node-args <args> | Additional runtime arguments | — |
--max-memory-restart <size> | Restart when memory exceeds limit | — |
--max-restarts <n> | Maximum consecutive restarts | 16 |
--min-uptime <ms> | Minimum uptime before a restart is considered stable | 1000 |
--restart-delay <ms> | Delay between restarts | 0 |
--kill-timeout <ms> | Grace period before SIGKILL | 5000 |
--no-autorestart | Disable automatic restart | false |
--cron <expression> | Cron expression for scheduled restarts | — |
--watch | Enable file watching | false |
--ignore-watch <dirs> | Directories to ignore | node_modules,.git |
--port <n> | Base port (auto-incremented in cluster mode) | — |
--namespace <ns> | Process namespace for grouping | — |
--on-ns-member-exit <policy> | Reaction to a namespace sibling’s terminal exit: ignore or exit (namespaced processes only) | ignore |
--depends-on <list> | Comma-separated dependencies (issue #33): name or name:optional each — pboss apps first, then systemd units | — |
--wait-ready | Wait for process ready signal | false |
--listen-timeout <ms> | Timeout waiting for ready signal | 3000 |
--source-map-support | Enable source map support | false |
--merge-logs | Merge all instance logs into one file | false |
--log-date-format <fmt> | Date format prefix for log lines | — |
--output <file> | Custom stdout log path | ~/.pboss/logs/<name>-<id>-out.log |
--error <file> | Custom stderr log path | ~/.pboss/logs/<name>-<id>-error.log |
--log-max-size <size> | Max log file size before rotation | 10M |
--log-retain <n> | Number of rotated log files to keep | 5 |
--log-compress | Gzip rotated log files | false |
--health-check-url <url> | HTTP endpoint for health probes | — |
--health-check-interval <ms> | Probe interval | 30000 |
--health-check-timeout <ms> | Probe timeout | 5000 |
--health-check-max-fails <n> | Failures before restart | 3 |
--no-daemon, -d | Run in foreground without a daemon (blocks) | false |
--raw | Also send child logs to stdout/stderr while retaining log files | false |
Flags are position-independent.
--no-daemon(and all other flags) may appear anywhere relative to the script path:pboss start --no-daemon app.ts pboss start app.ts --no-daemon pboss start --name api --no-daemon app.ts --watch
pboss stop#
Stop a process, all processes with a name, or all processes.
pboss stop 0
pboss stop my-api
pboss stop my-namespace
pboss stop all
A namespace target stops every member of the group (and only those), with a one-line summary naming the group. all on an empty list stays a no-op. Group stops are best-effort: a member that refuses to stop does not prevent the others, and the surviving errors are aggregated into one honest report.
Stopping is graceful by default: the process receives SIGTERM and has the kill timeout (default 5s) to exit before SIGKILL is sent.
Stopping a dependency (issue #33) prints a warning naming the processes that still require it — they keep running; only the warning tells you their dependency just went away:
[pboss] warning: stopping "postgres" — still required by "api". They keep running, but their required dependency will be unavailable until it is started again.
pboss restart#
Stop and restart a process. The process is fully stopped and then re-spawned — there will be downtime. For zero-downtime reloads, use reload.
pboss restart my-api
pboss restart my-namespace
pboss restart all
A namespace target restarts every member — including members that were stopped (restart on a stopped process starts it). The restart is atomic: stop-all, then an atomic start — if any member fails to come back, the members this restart brought up are rolled back, while members that never stopped (a failed stop) stay running.
Restart is dependency-aware (issue #33): required dependencies are pre-flighted before the stop, already-running ones are never restarted, and restarting a dependency never restarts its dependents. pboss restart api restarts api — not the postgres under it.
pboss reload#
Graceful zero-downtime reload. New instances start before old ones are killed, ensuring your application always has live workers handling requests.
pboss reload my-api
pboss reload my-namespace
pboss reload all
A namespace reload reloads every member, best-effort — one member failing to reload does not skip the rest of the group. (Atomicity does not apply: graceful reload is zero-downtime by design.)
The reload works per instance:
- A new process is spawned.
- pboss waits for it to become stable (or emit a ready signal when
--wait-readyis enabled). - The old process receives
SIGTERMand the kill timeout to shut down gracefully. - The cycle moves to the next instance.
pboss delete#
Stop and remove a process from pboss’s management.
pboss delete 0
pboss delete my-api
pboss delete my-namespace
pboss delete my-namespace --force
pboss delete all
Deleting a namespace removes every process in the group, best-effort — every member is removed even if one refuses to stop. Because that can take several processes at once, pboss asks for confirmation first — [y/N] in a terminal, and a hard refusal with a --force hint when stdin is not a TTY (scripts, CI, pipes). Name and cluster deletes keep their old unconfirmed behavior, as does delete all.
Deleting a dependency (issue #33) is refused when other processes still dependsOn it — pboss will not silently break their graph:
Error: Cannot delete "postgres" (postgres) — "api" still depends on it.
Those processes will fail to start until the dependency is restored or removed from their dependsOn.
Run with --force (CLI) or pass { force: true } (API) to delete it anyway.
--force overrides (it also skips the namespace confirmation above). Members removed together with their dependents — a namespace or all delete — do not trigger the refusal; nothing is left stranded.
pboss deps#
Inspect the dependency graph (issue #33): direct dependencies with their provider, state, and satisfaction.
pboss deps api
api
├── postgres [running] ProcBoss ✓
├── redis [running] ProcBoss ✓
├── postgresql [active] systemd ✓
└── metrics [not-found] systemd ✗ ~ (optional)
--reverse answers the other direction — who depends on this process:
pboss deps postgres --reverse
postgres
├── api [online]
└── worker [online]
Both views are direct relationships. A namespace target reports each member; a missing target is a clear error. Resolution runs for the report, but nothing is started — pboss deps is pure inspection. The same data is available programmatically via deps().
pboss scale#
Dynamically scale a process group up or down.
pboss scale my-api 8
pboss scale my-api 2
When scaling up, new instances inherit the configuration of existing instances. When scaling down, the highest-numbered instances are stopped and removed first.
pboss describe#
Show detailed information about a process.
pboss describe my-api
┌─────────────────────┬──────────────────────────────────────────┐
│ Name │ my-api-0 │
│ ID │ 0 │
│ Status │ online │
│ PID │ 4521 │
│ Exec Mode │ cluster │
│ Instances │ 4 │
│ Uptime │ 2h 15m │
│ Restarts │ 0 │
│ Unstable Restarts │ 0 │
│ CPU │ 0.3% │
│ Memory │ 42.1 MB │
│ File Handles │ 24 │
│ Script │ /home/user/app/server.ts │
│ CWD │ /home/user/app │
│ Interpreter │ bun │
│ Watch │ disabled │
│ Max Memory Restart │ 512 MB │
│ Health Check │ http://localhost:3000/health (healthy) │
│ Cron Restart │ disabled │
│ Namespace │ production │
│ Created │ 2025-02-11T10:30:00.000Z │
│ Out Log │ /home/user/.pboss/logs/my-api-0-out.log │
│ Error Log │ /home/user/.pboss/logs/my-api-0-error.log │
└─────────────────────┴──────────────────────────────────────────┘
pboss list#
List all managed processes with status, resource usage, and uptime. Supports a live mode with auto-refresh and interactive keyboard shortcuts.
pboss list
pboss list --live
Live mode keyboard shortcuts:
| Key | Action |
|---|---|
R | Reload table manually |
M | Sort by memory usage |
C | Sort by CPU usage |
U | Sort by uptime |
Q | Quit live mode |
Live mode refreshes the table every second by default; sorting can be changed on the fly with the shortcuts above.
pboss signal#
Send an OS signal to a process.
pboss signal my-api SIGUSR2
pboss reset#
Reset the restart counter for a process.
pboss reset my-api
pboss reset all