A JavaScript engine written entirely in safe Rust, with zero unsafe, that
targets the behavior of QuickJS 2026-06-04.
Its core, quickjs-oxide-core, compiles every function to register bytecode and runs
it in one loop with inline caches, over a NaN-boxed value heap and a
mark-sweep collector.
Within the Test262 scope that QuickJS 2026-06-04 runs, quickjs-oxide passes
81,441 of 83,562 variants (97.462%). QuickJS's test262.conf
skips the other 18,475 of the 102,037 variants; across the full corpus the
pass rate is 79.815%.
- Zero
unsafe. Every crate in the workspace setsunsafe_code = "forbid", so the compiler rejectsunsafeanywhere in the engine, the CLI and the WebAssembly bindings. The collector, the compiler, the loop, the regular expression engine and the Unicode tables are all safe Rust; the only third-party code in the engine isnum-bigintandnum-traits, for the front end's BigInt literals and the embedding API's BigInt values. - Performance close to QuickJS. On the 37 fixed-work programs of the
V8 v7, Octane 2.0 and AWFY suites, quickjs-oxide takes 0.94× QuickJS
2026-06-04's time over V8 v7's eight programs, 1.15× over Octane's 15 and
0.99× over AWFY's 14 (geometric means of release builds on one Linux
machine;
scripts/benchmark/suite_matrix.pyruns the matrix). - ECMAScript first, QuickJS where it is open. ECMA-262 and Test262 decide
correctness; QuickJS 2026-06-04 decides what the specification leaves to
the implementation (error messages,
stack, the printer, property order of the intrinsics), and a differential suite compares the two engines case by case. Five behaviors depart by decision:withis aSyntaxError, nothing readsSymbol.unscopables, directevalruns as indirect eval, a runtime has one realm, and nothing readsSymbol.species(deviation ledger). - Runs where you need it. A
qjscommand line, a Rust embedding API and a WebAssembly build.
Try it in the browser → The homepage computes a Mandelbrot set with the engine compiled to WebAssembly; the docs cover embedding, Rust functions, host services, modules, limits and performance.
GitHub Releases
carry prebuilt qjs binaries for Linux, macOS and Windows and WebAssembly
packages.
cargo binstall quickjs-oxide-cli
# or build from source with Rust 1.99 or newer
cargo install --locked quickjs-oxide-cliqjs -e 'console.log({ answer: 42 })'
qjs --print-result -e '(function (a) { return a + 1; })(41)' # 42
qjs module.mjs # ES modules: -m/--module, --script, or .mjs detection
qjs data.js arg1 arg2 # arguments are available as scriptArgsThe file loader follows QuickJS: .json imports are strict JSON, and
with { type: "json5" } selects QuickJS's extended JSON.
[dependencies]
quickjs-oxide = "0.4"
quickjs-oxide-host = "0.4"use quickjs_oxide::engine::api::core::{Runtime, Value};
use quickjs_oxide_host::SystemHost;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
let value = context.eval("[1, 2, 3].map((x) => x * 2).join()")?;
if let Value::String(text) = value {
println!("{}", text.to_utf8_lossy()); // 2,4,6
}
Ok(())
}A Rust closure becomes a JavaScript function; its arguments are converted to the closure's parameter types:
use quickjs_oxide::engine::api::core::{Runtime, Scope};
let runtime = Runtime::new();
let context = runtime.context();
let global = context.global_object()?;
context.define_function(&global, "add", 2, |_: &mut Scope<'_>, a: f64, b: f64| Ok(a + b))?;
assert_eq!(context.eval("add(40, 2)")?.as_number(), Some(42.0));examples/eval.rs handles every completion value and uncaught exceptions;
examples/host.rs shows host functions, a host object, a promise settled
from Rust, a native module and an interrupt.
Code compiled through eval/compile lives as long as the runtime; an
application that evaluates input repeatedly (a REPL) passes
EvalOptions::default().transient() so that each input's code is freed
once unreachable (code lifetime).
A host (SystemHost, or an application's own Host) supplies time,
randomness and output; a module loader lets an application resolve and load
ES modules. A runtime has one realm; separate runtimes isolate code.
The language, built-ins and ES modules (static and dynamic import,
top-level await, import attributes, JSON modules) follow ECMA-262 within
QuickJS 2026-06-04's feature set, apart from the five ledger entries above.
The std and os modules, the REPL, Worker, qjsc and the C API are not
yet supported; the Rust embedding API provides the C API's equivalents. Compatibility details the baseline,
how conformance is measured, the approved deviations and the full product
surface.
- Compatibility with QuickJS 2026-06-04
- Architecture, embedding internals and implementation status
- Test262 baseline and metrics
- Execution, the heap, performance and profiling
- The site and its docs, releases and the changelog
git clone https://github.com/pocket-nexus/quickjs-oxide.git
cd quickjs-oxide
cargo run --quiet --bin qjs -- examples/module-42.mjs # 42
cargo test --locked --workspace --all-targets
./scripts/test262/test-test262.sh --check
./scripts/test262/test-test262.sh --focused
TEST262_WORKERS=2 ./scripts/test262/test-test262.sh --full
npm ci && ./scripts/web/test-site.sh
npx playwright install chromium && npm run test:browserrust-toolchain.toml pins the toolchain. The core (bytecode, heap, loop and
builtins) lives in the quickjs-oxide-core crate (core/), the front end, the
register lowering and the embedding API in the root crate (src/), the
regular-expression engine and Unicode tables in the quickjs-oxide-regexp crate
(regexp/), host adapters in adapters/, the CLI and WebAssembly apps in
apps/, and the Test262 runner in conformance/test262; the
architecture guide describes each crate's
responsibilities.