Migrating JetStream 2.2 to Node.js: Challenges, Design, and What We Learned
- Rajeev Gadgil
- May 19
- 3 min read
Updated: 5 days ago
JetStream is a JavaScript benchmark suite that evaluates web application performance by measuring the execution latency and throughput of complex workloads. With the release of JetStream 2.2, we at WhileOne Techsoft undertook the task of migrating its harness to a modern Node.js-based setup.
Recently while working with a customer who was looking to benchmark their CPU using some js workloads.
This post dives into why we did it, how we did it, and what you can expect from the JetStream-on-Node.js v2 repo.
Background: Why Move to Node.js?
JetStream is browser-focused but heavily dependent on JavaScriptCore, V8, or other JS engines. Traditionally, it's driven via browser-based test harnesses, but for backend benchmarking and automation (especially for CPU benchmarking on headless systems), a Node.js-based execution layer is far more practical.
Key motivators:

Automated benchmarking in CI/CD environments.
Cross-platform compatibility, especially for non-GUI servers (ARM, RISC-V, etc.).
Easier integration with custom harnesses or profiling tools (like perf, time, etc.).
Remove reliance on browser UIs and move toward CLI-based, headless benchmarks.
Architecture Overview
We restructured JetStream 2.2 to run under Node.js with minimal dependency changes. The project now:
Loads JetStream benchmarks as CommonJS/ES modules.
Mocks browser-specific globals (window, document, etc.) only where needed.
Handles timing and result reporting within Node.
Adds CLI support for automated runs.
Project structure highlights:
JetStream-Node/
├── benchmarks/
├── driver/
│ ├── main.js ← CLI runner
│ ├── harness.js ← Benchmark orchestrator
│ └── fake-browser.js ← Global mocks
├── results/
├── utils/
├── package.json
Migration Strategy
We broke the migration into several focused steps:

1. Browser Shim Implementation
JetStream’s benchmarks expect a browser-like environment. We built a lightweight shim that defines:
window, document, performance.now()
setTimeout, clearTimeout
Custom stubs for HTML elements (e.g., CanvasRenderingContext2D)
This shim lives in driver/fake-browser.js and is injected before benchmarks are loaded.
2. Rewriting the Test Harness
Instead of using JetStream's HTML runner, we built a new runner in driver/harness.js that:
Iterates over all benchmark modules.
Loads and runs them with a warm-up + main execution loop.
Times each run with performance.now() or process.hrtime.
3. CommonJS Compatibility Fixes
Some benchmarks had inline scripts or relied on document.write. We:
Wrapped them in modules where possible.
Rewrote some legacy benchmark entry points using require() or import().
Adjusted globals to match what the benchmark expects.
4. Result Logging and Aggregation
Each benchmark result is recorded in JSON format in the results/ folder. We compute:
Raw latency times.
Geometric means.
Per-benchmark scores.
This structure allows easy post-processing or integration into other tools.
What Works (and What’s Left)
Working:
Full benchmark execution under Node 20+.
Logging, scoring, and isolation of benchmark outputs.
Runs across x86 and ARM64.
Still to refine:
Some benchmarks that depend on browser layout (e.g., DOM-heavy tests) are disabled or stubbed.
Parallel execution and profiling hooks are planned.
Rewriting result UI for visualization (low priority for CLI users).
Usage
To try it yourself:
cd JetStream-Node git checkout jetstream-on-node-js-v2 npm install node driver/main.js
This will run the benchmark suite and save output under results/.
Performance Use Cases

Server CPU benchmarking: Run JetStream as part of CPU regression testing on headless servers.
CI integration: Track JS performance changes across commits or platforms.
Cross-architecture comparison: Run the same benchmark on x86, ARM64, RISC-V, and compare results meaningfully.
Future Work
Add --filter and --repeat CLI flags.
Support native engine plugins (e.g., run with SpiderMonkey via CLI).
Add CSV and HTML result output formats.
Final Thoughts
Migrating JetStream 2.2 to Node.js wasn’t just a port—it was about transforming it into a modern, scriptable, backend-compatible benchmarking tool. If you're looking to run JetStream without a browser, or to integrate it into your infrastructure, this project is a clean, extensible starting point.
You can check out the source and contribute here: GitHub - https://github.com/Whileone-Techsoft/JetStream-Node/tree/jetstream-on-node-js-v2
Comentários