Measured Node.js 22.12.0
Benchmarks
node-cmd delegates to Node’s own child-process primitives. These measurements isolate the JavaScript wrapper and then time real child completion, so convenience never hides its cost.
The wrapper stays beneath the work it controls
Common callback, Promise, direct-file, and streaming paths added medians of 0.21–0.22 ns over the matching node:child_process call. The two synchronous result envelopes added 7.56 ns and 10.40 ns. Even the larger value is about 3.8 million times smaller than its matching empty-process completion time.
Nanoseconds before a process exists
The child-process functions were replaced temporarily with counter stubs in an isolated measurement setup. This removes operating-system launch noise and exposes only argument normalization, result-envelope construction, and function dispatch. Bars show median nanoseconds per call; lower is better.
runrunPromiserunSyncrunFilerunFilePromiserunFileSyncrunStream| node-cmd API | Paired median delta | 95% bootstrap CI | Interpretation |
|---|---|---|---|
run | +0.211 ns | +0.203 to +0.220 | Dispatch measured |
runPromise | +0.217 ns | +0.209 to +0.229 | Dispatch measured |
runSync | +7.562 ns | +7.486 to +7.614 | Result normalization measured |
runFile | +0.211 ns | +0.204 to +0.219 | Overload dispatch measured |
runFilePromise | +0.213 ns | +0.204 to +0.224 | Overload dispatch measured |
runFileSync | +10.402 ns | +10.241 to +10.484 | Options + result normalization measured |
runStream | +0.218 ns | +0.204 to +0.227 | Overload dispatch measured |
The wrapper tracks Node through the operating system
Each implementation started the same empty Node.js executable with identical options. The run* scenarios include the platform shell plus that child; runFile* and runStream() start the child directly. The direct and node-cmd calls ran sequentially, with first position alternating to reduce order bias. Bars show median completion time; lower is better.
run · callbackrunPromiserunSyncrunFile · callbackrunFilePromiserunFileSyncrunStream| node-cmd API | Node direct p50 | node-cmd p50 | Paired-delta 95% CI |
|---|---|---|---|
run | 53.040 ms | 52.859 ms | −0.716 to +0.235 ms |
runPromise | 53.712 ms | 53.787 ms | −0.985 to +0.600 ms |
runSync | 54.495 ms | 54.617 ms | −0.853 to +1.536 ms |
runFile | 42.452 ms | 41.932 ms | −1.145 to +0.146 ms |
runFilePromise | 40.393 ms | 40.140 ms | −1.135 to +0.460 ms |
runFileSync | 39.508 ms | 39.485 ms | −0.793 to +0.189 ms |
runStream | 39.121 ms | 38.886 ms | −0.874 to +0.218 ms |
All seven paired-delta confidence intervals include zero, so this run did not resolve a completion-time difference. That is a statement about detection at this sample size—not proof that the implementations are mathematically equivalent.
Reference environment and controls
| Input | Reference value | Why it matters |
|---|---|---|
| Runtime | Node.js 22.12.0 · V8 12.4 | The exact supported runtime floor |
| Source identity | SHA-256 for runtime and both benchmark scripts | Full hashes are included in the raw report |
| Host | Windows x64 · Intel Core Ultra 9 275HX · 24 logical CPUs | Absolute launch time is machine-specific |
| Process suite | 20 warm-ups + 100 balanced pairs per API | Sequential calls and alternating order reduce interference |
| Dispatch suite | 100 calibrated batches per API | At least 100,000 calls per batch; raw batches retained |
| Intervals | 2,000 deterministic bootstrap resamples | Reports uncertainty around the paired median |
| Source parity | CommonJS and ESM identity asserted before timing | Both module systems use the same implementation |
Run the dependency-free harness yourself
node ./benchmark/run.js --samples 100 --warmups 20 --output ./benchmark/reference.json
npm run benchmark:chart
The harness uses Node built-ins only. It preserves every process pair and dispatch batch in benchmark-results.json; the README charts are regenerated directly from that file.