vexord 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +293 -16
  2. package/package.json +47 -6
package/README.md CHANGED
@@ -1,25 +1,302 @@
1
- # vexord
1
+ <div align="center">
2
2
 
3
- **Pre-alpha.** Rust-native process manager for Node.js apps, aiming for PM2
4
- compatibility. This package installs the `vexor` command.
3
+ # Vexor
4
+
5
+ **The production process manager for Node.js: a faster, safer upgrade to PM2.**
6
+
7
+ Written in Rust. Runs your PM2 ecosystem files as they are, keeps apps running
8
+ even when the supervisor crashes, and moves your apps off PM2 with one
9
+ reversible command.
10
+
11
+ [![npm](https://img.shields.io/npm/v/vexord?label=npm%20vexord&color=14b8a6)](https://www.npmjs.com/package/vexord)
12
+ [![CI](https://github.com/gauravgitgithub/vexor/actions/workflows/ci.yml/badge.svg)](https://github.com/gauravgitgithub/vexor/actions/workflows/ci.yml)
13
+ [![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](#license)
14
+ ![Platforms](https://img.shields.io/badge/platforms-Linux%20x64%20%7C%20arm64%20%7C%20macOS-555)
5
15
 
6
16
  ```sh
7
17
  npm install -g vexord
8
- vexor start app.js -i 2
9
- vexor list
10
18
  ```
11
19
 
12
- npm installs the prebuilt binary for your platform as an optional dependency
13
- (`vexord-linux-x64`, `vexord-linux-arm64`, `vexord-darwin-arm64`,
14
- `vexord-darwin-x64`). There are no install scripts and no downloads at install
15
- time. If optional dependencies are disabled, `vexor` tells you how to fix it.
20
+ [Why Vexor](#why-vexor) · [Benchmarks](#benchmarks) · [Compare](#vexor-vs-pm2-oxmgr-and-forever) · [Migrate from PM2](#migrate-from-pm2-in-four-commands) · [FAQ](#faq)
21
+
22
+ </div>
23
+
24
+ ## What is Vexor?
25
+
26
+ Vexor is an open-source process manager for Node.js applications in
27
+ production: it starts your apps, keeps them running, restarts them when they
28
+ crash, runs them in cluster mode across CPU cores, reloads them without
29
+ downtime, and manages their logs. It is compatible with PM2: the same
30
+ `ecosystem.config.js`, the same commands (`start`, `stop`, `restart`,
31
+ `reload`, `logs`, `save`, `startup`), and a built-in migration from PM2 with
32
+ a dry run, a backup and a rollback.
33
+
34
+ Unlike PM2, Vexor's supervisor is a single static binary written in Rust: it
35
+ doesn't need Node.js to run, uses a fraction of PM2's memory, and answers
36
+ commands several times faster. Each app has its own small supervisor, so your
37
+ apps keep running and stay managed even if the main daemon crashes or is
38
+ upgraded.
39
+
40
+ > **Status: prerelease (0.3).** Used for evaluation and real migrations;
41
+ > see the [changelog](https://github.com/gauravgitgithub/vexor/blob/main/CHANGELOG.md) and the [known limits](#is-vexor-production-ready).
42
+
43
+ ## Why Vexor
44
+
45
+ - **Your apps survive the supervisor.** Kill the Vexor daemon with `kill -9`
46
+ and your apps keep serving and stay managed: 0 failed requests in our
47
+ test, against 739 failed requests and a lost app with PM2.
48
+ - **A fast CLI.** `vexor ls` answers in 23 ms; `pm2 ls` takes 76 ms.
49
+ - **Light.** 5.7 MiB of supervisor memory for one app against PM2's 33 MiB,
50
+ idle CPU close to zero, and a 5.8 MiB install against PM2's 17 MiB.
51
+ - **Zero-downtime reloads.** New processes start and must be healthy before
52
+ the old ones are retired; a failed reload keeps the old processes.
53
+ - **Built-in health checks** (HTTP or TCP): an app is ready when its first
54
+ check passes and is restarted when it stops answering. PM2 has no
55
+ built-in HTTP health checks.
56
+ - **One log timeline.** `vexor logs` merges every app's output by time, each
57
+ line with its timestamp, the app name in its own colour and stderr marked.
58
+ JSON logs (pino, winston) are shown as level, message and fields.
59
+ - **Safe migration from PM2.** `vexor migrate --from-pm2` plans the move,
60
+ backs up PM2's state, moves apps one at a time, puts any app that fails
61
+ back on PM2, and can roll everything back.
62
+ - **Runs any Node.js version.** Apps on Node 8 through 24 are tested in CI;
63
+ the supervisor itself needs no Node at all.
64
+ - **Secure by default.** State and logs are private to your user (0600),
65
+ apps get an allowlisted environment unless you ask for the whole shell's,
66
+ `describe` hides environment values, and release binaries ship with
67
+ SHA-256 checksums, an SBOM and build provenance.
68
+
69
+ ## Install
70
+
71
+ ```sh
72
+ npm install -g vexord # installs the `vexor` command
73
+ ```
74
+
75
+ Without npm or Node.js (verifies the SHA-256 checksum before installing):
76
+
77
+ ```sh
78
+ curl -fsSL https://raw.githubusercontent.com/gauravgitgithub/vexor/main/install.sh | sh
79
+ ```
80
+
81
+ Prebuilt for Linux x64 and arm64 (static, any distribution) and macOS arm64
82
+ and x64. No install scripts run during `npm install`.
83
+
84
+ ## Quick start
85
+
86
+ ```sh
87
+ vexor start app.js -i 4 # cluster mode, 4 instances
88
+ vexor start ecosystem.config.js # PM2 ecosystem files work as they are
89
+ vexor ls # status, CPU, memory, uptime, restarts
90
+ vexor logs -f # one timeline of every app's logs
91
+ vexor reload app # new processes first, then retire the old
92
+ vexor describe app # configuration, status, recent events
93
+ vexor startup # start at boot (systemd, launchd)
94
+ ```
95
+
96
+ ## Migrate from PM2 in four commands
97
+
98
+ ```sh
99
+ pm2 save # make PM2's saved list current
100
+ vexor migrate --from-pm2 # dry run: the plan, changes nothing
101
+ vexor migrate --from-pm2 --backup # back up PM2's state and the plan
102
+ vexor migrate --from-pm2 --apply # move apps one at a time
103
+ ```
104
+
105
+ The dry run shows, for each app, whether it can move and what needs your
106
+ attention (an app PM2 keeps restarting, a missing script, a readable dump
107
+ file). `--apply` stops each app under PM2, starts it under Vexor, and waits
108
+ until it is healthy; an app that isn't goes straight back to PM2. Changed
109
+ your mind? `vexor migrate --rollback` moves everything back. Each running
110
+ app is down for about its start-up time while it moves. Details:
111
+ [docs/migration.md](https://github.com/gauravgitgithub/vexor/blob/main/docs/migration.md).
112
+
113
+ ## Benchmarks
114
+
115
+ Vexor 0.3.1 against PM2 7.1.0, OxMgr 0.5.0 (another Rust process manager)
116
+ and forever 4.0.3, each installed from npm and run alone on the same apps
117
+ in one Linux container. Every number below was measured; the harness is in
118
+ [`benchmarks/`](https://github.com/gauravgitgithub/vexor/blob/main/benchmarks/) and the raw results are
119
+ [committed](https://github.com/gauravgitgithub/vexor/blob/main/benchmarks/results/2026-10-23-apple-m5-docker/results.json).
120
+
121
+ <p align="center">
122
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/supervisor-memory.svg" alt="Supervisor memory: Vexor, PM2, OxMgr, forever" width="760"><br>
123
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/cli-latency.svg" alt="CLI response time" width="760"><br>
124
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/start-time.svg" alt="Time to start 10 apps" width="760"><br>
125
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/supervisor-cpu.svg" alt="Supervisor CPU while idle" width="760"><br>
126
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/crash-restart.svg" alt="Crash to back online" width="760"><br>
127
+ <img src="https://cdn.jsdelivr.net/gh/gauravgitgithub/vexor@main/docs/benchmarks/install-size.svg" alt="Installed size" width="760">
128
+ </p>
129
+
130
+ Measured 2026-10-23 on Apple M5 (Docker Desktop VM) (10 cores, 8 GB), linux/arm64 7.0.12-linuxkit, in a container, Node v22.23.4. Each tool runs alone, installed from npm, on the same apps. **Bold** = best; n/a = not supported or failed (see notes).
131
+
132
+ | Measure | Vexor 0.3.1 | PM2 7.1.0 | OxMgr 0.5.0 | forever 4.0.3 |
133
+ |---|---|---|---|---|
134
+ | List apps (CLI), median | **23 ms** | 76 ms | 24 ms | 109 ms |
135
+ | Start 10 apps until online, median | 352 ms | 435 ms | **317 ms** | 1268 ms |
136
+ | Supervisor memory (PSS), 1 app | 5.7 MiB | 33 MiB | **3.5 MiB** | 37 MiB |
137
+ | Supervisor memory (PSS), 10 apps | 7.9 MiB | 21 MiB | **5.7 MiB** | 191 MiB |
138
+ | Supervisor memory (PSS), 50 apps | 17 MiB | 21 MiB | **4.6 MiB** | 825 MiB |
139
+ | Supervisor memory (RSS), 1 app | 8.1 MiB | 66 MiB | **3.5 MiB** | 67 MiB |
140
+ | Supervisor memory (RSS), 10 apps | 33 MiB | 68 MiB | **5.7 MiB** | 675 MiB |
141
+ | Supervisor memory (RSS), 50 apps | 140 MiB | 72 MiB | **4.6 MiB** | 3316 MiB |
142
+ | Supervisor CPU while idle, 1 app | **0.00%** | 0.37% | 0.07% | 0.37% |
143
+ | Supervisor CPU while idle, 10 apps | **0.00%** | 0.70% | 0.07% | 2.26% |
144
+ | Supervisor CPU while idle, 50 apps | 0.33% | 1.50% | **0.17%** | 7.48% |
145
+ | Crash to back online, median | 38 ms | 159 ms | 20 ms | **13 ms** |
146
+ | Failed requests in 5 cluster reloads | **0** | **0** | **0** | n/a |
147
+ | Supervisor daemon killed: failed requests | **0** | 739 | **0** | n/a |
148
+ | Supervisor daemon killed: app still managed | **yes** | no | **yes** | n/a |
149
+ | Installed size (npm) | 5.8 MiB | 17 MiB | **3.9 MiB** | 20 MiB |
150
+
151
+ Requests sent: reloads Vexor 1615, PM2 1726, OxMgr 1645, forever 0; daemon kill Vexor 1239, PM2 1219, OxMgr 1220, forever 0.
152
+
153
+ Notes:
154
+ - OxMgr, crash_restart_ms: Measured separately: OxMgr marks an app errored after its 3rd crash by default (crash_restart_limit 3), even with uptime between crashes, so only 3 restarts can be timed.
16
155
 
17
- The launcher needs Node.js 10 or newer. The apps you run with vexor can use
18
- any Node.js version, including older ones, and vexor itself does not need
19
- Node.js: on machines without a suitable Node, install the binary directly with
20
- `install.sh` from the repository.
156
+ **Where Vexor wins.** Against PM2: 3× faster CLI, about 6× less supervisor
157
+ memory for one app, less idle CPU, faster starts, faster crash recovery, a
158
+ third of the install size, and the app keeps running and stays managed when
159
+ the supervisor is killed (PM2 lost the app and 739 requests). Against
160
+ forever: on every measure Vexor supports, and forever has no cluster mode,
161
+ reload or daemon.
162
+
163
+ **Where Vexor loses, and what we're doing about it.**
164
+
165
+ - **Memory against OxMgr.** OxMgr runs one daemon for all apps; Vexor runs a
166
+ small supervisor (shim) per app, which is what keeps apps managed when the
167
+ daemon dies. Measured as PSS, Vexor uses 17 MiB at 50 apps (PM2 21 MiB,
168
+ OxMgr 4.6 MiB); measured as RSS, which counts the shared binary once per
169
+ shim, 140 MiB. Shrinking the per-app shim is on the roadmap.
170
+ - **Crash restarts** take 38 ms, against 13 ms for forever and 20 ms for
171
+ OxMgr (PM2: 159 ms). Note that OxMgr, by default, stops restarting an app
172
+ after its 3rd crash, even when it ran for seconds in between.
173
+ - **Install size and start time:** OxMgr is smaller (3.9 MiB) and slightly
174
+ faster to start 10 apps (317 ms against 352 ms).
175
+ - **Windows:** PM2, OxMgr and forever run on Windows; Vexor doesn't yet.
176
+
177
+ Methodology and how to reproduce: [docs/benchmarks.md](https://github.com/gauravgitgithub/vexor/blob/main/docs/benchmarks.md).
178
+
179
+ ## Vexor vs PM2, OxMgr and forever
180
+
181
+ | | Vexor | PM2 | OxMgr | forever |
182
+ |---|---|---|---|---|
183
+ | Runs PM2 `ecosystem.config.js` as is | ✓ | ✓ | ~ ¹ | ✗ |
184
+ | Migrates running PM2 apps (plan, backup, apply, rollback) | ✓ | – | ✗ ² | ✗ |
185
+ | Cluster mode (shared port across CPU cores) | ✓ | ✓ | ✓ | ✗ |
186
+ | Zero-downtime reload, health-gated | ✓ | ✓ | ✓ | ✗ |
187
+ | Apps keep running and stay managed if the daemon is killed | ✓ ³ | ✗ ³ | ✓ ³ | – |
188
+ | HTTP/TCP health checks | ✓ | ✗ | command checks | ✗ |
189
+ | Restart on memory limit / cron / file change | ✓ / ✓ / ✓ | ✓ / ✓ / ✓ | ✓ / ✓ / ✓ | ✗ / ✗ / ✓ |
190
+ | Built-in log rotation | ✓ | module (pm2-logrotate) | ✓ | ✗ |
191
+ | One merged, timestamped log timeline | ✓ | per app ⁴ | ✗ | ✗ |
192
+ | Start at boot (systemd, launchd) | ✓ | ✓ | ✓ | ✗ |
193
+ | Supervisor needs no Node.js | ✓ | ✗ | ✓ | ✗ |
194
+ | Windows | ✗ | ✓ | ✓ | ✓ |
195
+ | License | MIT or Apache-2.0 | AGPL-3.0 | MIT | MIT |
196
+
197
+ ✓ supported · ✗ not supported · ~ partly · – not applicable.
198
+ ¹ In our test, importing a PM2 ecosystem file with `.js` scripts failed ("failed to spawn"); `node script.js` commands work.
199
+ ² OxMgr converts ecosystem files; it doesn't document moving apps from a running PM2 with rollback.
200
+ ³ Measured: `kill -9` of the daemon under HTTP load (see [Benchmarks](#benchmarks)).
201
+ ⁴ `pm2 logs` interleaves apps; lines carry timestamps only with `time: true` or `log_date_format`.
202
+ OxMgr and forever capabilities are from their documentation and CLI help (OxMgr 0.5.0, forever 4.0.3) and our tests.
203
+
204
+ ## Features
205
+
206
+ | | |
207
+ |---|---|
208
+ | Process management | fork and cluster mode, instances, restart with backoff and crash-loop limit, `stop_exit_codes`, graceful stop with `kill_timeout` and a configurable signal |
209
+ | Zero downtime | `reload`: new processes first, healthy before the old ones retire; failed reloads keep the old processes |
210
+ | Health | `wait_ready` (`process.send('ready')`), HTTP/TCP health checks, `max_memory_restart`, `cron_restart`, `watch` |
211
+ | Logs | timestamped lines, one merged timeline, built-in rotation (10 MiB × 5 by default), back-pressure control |
212
+ | Reliability | per-app supervisors survive daemon crashes and upgrades; PID identity checks against PID reuse; orphaned descendants cleaned up |
213
+ | PM2 compatibility | ecosystem files (`.js`, `.cjs`, `.mjs`, `.json`), `vexor check` lists every unsupported setting before you start, conformance-tested against PM2 7 |
214
+ | Operations | `save`/`resurrect`, `startup` for systemd and launchd, `describe`, `events` history, `--json` everywhere |
215
+
216
+ ## FAQ
217
+
218
+ ### What is the best alternative to PM2?
219
+
220
+ If you want to keep PM2's ecosystem files and commands but need a lighter,
221
+ faster supervisor whose crashes don't take your apps with it, Vexor is
222
+ built for that, and it migrates your PM2 apps for you. For apps that only
223
+ need restarts on one Linux host, plain systemd units are also an option,
224
+ without cluster mode or log management.
225
+
226
+ ### Is Vexor a drop-in replacement for PM2?
227
+
228
+ For most setups, yes: the same ecosystem files and commands work. Run
229
+ `vexor check ecosystem.config.js` to see any setting Vexor handles
230
+ differently or doesn't support; today that is `uid`/`gid`, `increment_var`
231
+ and `shutdown_with_message`. Differences are documented in
232
+ [docs/compatibility.md](https://github.com/gauravgitgithub/vexor/blob/main/docs/compatibility.md) and checked against PM2 7 in
233
+ [docs/conformance.md](https://github.com/gauravgitgithub/vexor/blob/main/docs/conformance.md).
234
+
235
+ ### How do I migrate from PM2 to Vexor?
236
+
237
+ `pm2 save`, then `vexor migrate --from-pm2` (a dry run), `--backup`, and
238
+ `--apply`. Apps move one at a time and any app that isn't healthy under
239
+ Vexor goes back to PM2. `vexor migrate --rollback` undoes the migration.
240
+
241
+ ### Does Vexor support cluster mode and zero-downtime reloads?
242
+
243
+ Yes. `vexor start app.js -i 4` (or `exec_mode: "cluster"`) runs Node's
244
+ cluster mode, sharing the port between instances. `vexor reload` starts new
245
+ workers, waits until they are ready, then retires the old ones; our tests
246
+ saw 0 failed requests across repeated reloads under load.
247
+
248
+ ### What happens if the Vexor daemon crashes?
249
+
250
+ Nothing visible to your apps. Each app is supervised by its own small
251
+ process (a shim); the daemon only coordinates. A new daemon reconnects to
252
+ the running apps. In our test, `kill -9` of the daemon caused 0 failed
253
+ requests and the app stayed managed.
254
+
255
+ ### Which Node.js versions does Vexor support?
256
+
257
+ Apps on Node.js 8 through 24 are tested in CI. The `vexor` supervisor is a
258
+ native binary and needs no Node.js; the npm launcher needs Node 10 or newer,
259
+ and `install.sh` installs without Node.
260
+
261
+ ### Does Vexor run on Windows?
262
+
263
+ Not yet. Linux (x64, arm64) and macOS (arm64, x64) are supported.
264
+
265
+ ### Is Vexor production ready?
266
+
267
+ Vexor is a prerelease (0.3). It is tested in CI on Linux and macOS, against
268
+ real PM2 for compatibility, and through real migrations, and its weak points
269
+ are published with the [benchmarks](#benchmarks). Try it on a staging host
270
+ first, and keep PM2's rollback path until you are confident.
271
+
272
+ ### Is Vexor free?
273
+
274
+ Yes: open source under MIT or Apache-2.0, with no paid tier. Health checks,
275
+ log rotation and the event history are built in.
276
+
277
+ ## Documentation
278
+
279
+ [Architecture](https://github.com/gauravgitgithub/vexor/blob/main/docs/architecture.md) ·
280
+ [Compatibility with PM2](https://github.com/gauravgitgithub/vexor/blob/main/docs/compatibility.md) ·
281
+ [PM2 conformance results](https://github.com/gauravgitgithub/vexor/blob/main/docs/conformance.md) ·
282
+ [Migration](https://github.com/gauravgitgithub/vexor/blob/main/docs/migration.md) ·
283
+ [Benchmarks and methodology](https://github.com/gauravgitgithub/vexor/blob/main/docs/benchmarks.md) ·
284
+ [Security](https://github.com/gauravgitgithub/vexor/blob/main/docs/security.md) ·
285
+ [Roadmap](https://github.com/gauravgitgithub/vexor/blob/main/docs/plan.md) ·
286
+ [Changelog](https://github.com/gauravgitgithub/vexor/blob/main/CHANGELOG.md)
287
+
288
+ ## Development
289
+
290
+ The toolchain is pinned in `rust-toolchain.toml`.
291
+
292
+ ```sh
293
+ cargo fmt --all --check
294
+ cargo clippy --workspace --all-targets --locked -- -D warnings
295
+ cargo test --workspace --locked
296
+ cargo deny check all # needs cargo-deny
297
+ ```
21
298
 
22
- Documentation, compatibility notes and source:
23
- https://github.com/gauravgitgithub/vexor
299
+ ## License
24
300
 
25
- License: MIT OR Apache-2.0.
301
+ Licensed under either of [Apache License 2.0](https://github.com/gauravgitgithub/vexor/blob/main/LICENSE-APACHE) or
302
+ [MIT license](https://github.com/gauravgitgithub/vexor/blob/main/LICENSE-MIT), at your option.
package/package.json CHANGED
@@ -1,8 +1,49 @@
1
1
  {
2
2
  "name": "vexord",
3
- "version": "0.2.0",
4
- "description": "Rust-native process manager for Node.js apps (pre-alpha). Installs the `vexor` command.",
3
+ "version": "0.3.1",
4
+ "description": "The PM2 alternative written in Rust: run Node.js apps in production with zero-downtime reloads, cluster mode, health checks, timestamped logs and one-command migration from PM2. Installs the `vexor` command.",
5
+ "keywords": [
6
+ "pm2",
7
+ "pm2-alternative",
8
+ "pm2-replacement",
9
+ "process-manager",
10
+ "process manager",
11
+ "node process manager",
12
+ "nodejs",
13
+ "node",
14
+ "production",
15
+ "cluster",
16
+ "cluster-mode",
17
+ "zero-downtime",
18
+ "reload",
19
+ "graceful-reload",
20
+ "daemon",
21
+ "supervisor",
22
+ "keep-alive",
23
+ "auto-restart",
24
+ "health-check",
25
+ "log-rotation",
26
+ "logs",
27
+ "cron",
28
+ "watch",
29
+ "ecosystem",
30
+ "ecosystem.config.js",
31
+ "migration",
32
+ "pm2-migration",
33
+ "systemd",
34
+ "launchd",
35
+ "devops",
36
+ "rust",
37
+ "forever",
38
+ "deployment",
39
+ "uptime"
40
+ ],
41
+ "homepage": "https://github.com/gauravgitgithub/vexor#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/gauravgitgithub/vexor/issues"
44
+ },
5
45
  "license": "MIT OR Apache-2.0",
46
+ "author": "Gaurav Raj Sinha",
6
47
  "repository": {
7
48
  "type": "git",
8
49
  "url": "git+https://github.com/gauravgitgithub/vexor.git"
@@ -20,9 +61,9 @@
20
61
  "node": ">=10"
21
62
  },
22
63
  "optionalDependencies": {
23
- "vexord-darwin-arm64": "0.2.0",
24
- "vexord-darwin-x64": "0.2.0",
25
- "vexord-linux-arm64": "0.2.0",
26
- "vexord-linux-x64": "0.2.0"
64
+ "vexord-darwin-arm64": "0.3.1",
65
+ "vexord-darwin-x64": "0.3.1",
66
+ "vexord-linux-arm64": "0.3.1",
67
+ "vexord-linux-x64": "0.3.1"
27
68
  }
28
69
  }