JavaScript engines
Checked against f15b998 on 2026-11-10. The files it covers are unchanged since.
niso’s DOM is in Rust, and a page’s JavaScript runs on an engine bound to it
through one small interface (bindings/js/niso_engine.h: host functions, weak
references, finalizers, microtasks). The JS binding on top (bindings/js/niso_js.c, the
glue and the host functions generated from WebIDL) is the same on every
engine, so the same page runs on each and can be diffed.
| Engine | Crate | Where | Status |
|---|---|---|---|
| QuickJS-ng | niso-quickjs |
every host, niso-run |
the default; an interpreter, so it runs on iOS |
| V8, JavaScriptCore (via Node, Deno, Bun) | niso-napi |
niso-node |
headless only; a JIT without shipping one (Node-API) |
| Porffor | niso-porffor |
Apple and Android hosts with NISO_ENGINE=porffor, headless |
experimental: compiles the page’s JS to C ahead of time (Porffor) |
V8 embedded directly (desktop and Android) and JavaScriptCore on Apple platforms are planned, not built.
What the engine changes
Section titled “What the engine changes”The engine runs your code; everything else (the DOM, style, layout, events,
timers, fetch, storage) is the same Rust core whichever engine runs. So a page
behaves the same on each, apart from the language itself: speed, error
messages, and engine-specific gaps. Porffor, for one, has no eval at run
time and its WeakRef holds its target strongly.
Intl comes from niso, not the engine: QuickJS has none, so niso-quickjs
adds one built on ICU4X (crates/niso-intl, Intl).
WebAssembly
Section titled “WebAssembly”WebAssembly runs on wasmi, an interpreter in the core, on every platform, since iOS forbids JIT (WebAssembly). Under Node-API a page’s WebAssembly is V8’s own.
Native apps
Section titled “Native apps”Native apps (C, Rust, Swift, Java, …) use no JS engine: they call the same DOM through the C API directly (Native apps).