One shared TCP contract

Node.js and Rust, every role combination.

The release harness measures the same validated framed round trip with each runtime acting as client and server. Timing, memory, package size, provenance, and cleanup stay visible without turning smoke output into evidence.

4 lanes1,000,000 round tripsWindows · Linux · macOS

Tracked 14.0.0 matrix

Complete official batch accepted.

GitHub Actions run 32622520570 recorded Windows, Linux, and macOS at commit 2692d32 with Node.js 24.18.1 and Rust 1.85.0. All 60 fresh process pairs exited naturally; zero active processes, sockets, forced terminations, or temporary entries remained.

Median time per million round trips

Median milliseconds for the four Node.js and Rust TCP client-server lanes on Linux, macOS, and Windows
Fixed platform and lane order prevents timing-based sorting. One validated round trip is two application frames. Compare roles within one hosted platform; runner hardware differs across platforms.
PlatformNode → NodeNode → RustRust → NodeRust → Rust
Linux · x6410,312 ms9,317 ms16,816 ms12,478 ms
macOS · arm647,817 ms7,368 ms8,165 ms5,596 ms
Windows · x6412,609 ms15,231 ms23,186 ms13,070 ms

Each value is the median of five samples. Quick-smoke timings are excluded.

Four direct lanes

LaneClientServerPurpose
node-nodeNode.jsNode.jsSame-runtime Node.js control
node-rustNode.jsRustNode.js client interoperability
rust-nodeRustNode.jsRust client interoperability
rust-rustRustRustSame-runtime Rust control

Lane names always read client → server. Each sample starts a fresh release-built client, server, loopback port, and temporary directory.

Fixed full workload

SettingValue
Warm-up100,000 validated round trips
Measured work1,000,000 validated round trips; 2,000,000 application frames
Payload64 deterministic bytes
Maximum in flight64
Samples5 per lane; 20 fresh process pairs
ToolchainsNode.js 24.18.1 and Rust 1.85.0
The client owns the comparative timer.

Compilation, startup, warm-up, package measurement, parent garbage collection, and cleanup remain outside it. Every response is still checked for type, payload, sequence, count, and wire bytes.

Cleanliness and footprint

Processes + sockets

Both peers must exit naturally with code zero, their exact process IDs must be absent, and the endpoint must bind again.

Memory

Child RSS is sampled with the native platform facility and labelled as a sampled maximum, not an exact lifetime peak.

Packages

npm pack --dry-run and cargo package report compressed bytes, unpacked npm bytes, file counts, and hashes.

Temporary state

Every peer-specific directory must be empty and removed. A forced termination or sampler failure rejects full evidence.

Same-runtime sampled RSS and package size

PlatformNode client / serverRust client / servernpm packed / unpackedcrate packed
Linux118.9 / 69.3 MiB17.3 / 2.3 MiB26.2 / 98.2 KiB55.6 KiB
macOS114.9 / 66.4 MiB16.8 / 1.8 MiB26.2 / 98.2 KiB55.6 KiB
Windows103.4 / 54.2 MiB19.2 / 4.4 MiB26.4 / 101.1 KiB56.3 KiB

RSS rows use the Node→Node and Rust→Rust controls. Package values are the exact dry-run artifacts at measured commit 2692d32; later evidence-only documentation can change package bytes without changing the measured runtime. Runner checkout representation also causes small platform differences. Every raw record retains exact bytes, file counts, and hashes.

Run it

npm run benchmark:rust:test
npm run benchmark:rust:quick

# Official CI only; requires a clean main checkout.
npm run benchmark:rust:record -- --output-directory=<artifact-directory>

Quick mode validates all four lanes with a small workload and explicitly disables performance claims. The official workflow records the full configuration on each supported operating system and uploads sanitized JSON for strict three-platform merge.

Comparison boundary

These results compare one framed TCP workload on the named hosted runner, commit, architecture, and exact toolchains. They are not a universal language ranking, certification, browser claim, or substitute for an application-specific benchmark.