Skip to content

About

An independent Rust rewrite of QuickJS targeting semantic feature parity

Topics

Resources

Stars

81 stars

Watchers

1 watching

Forks

Repository files navigation

quickjs-oxide

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 sets unsafe_code = "forbid", so the compiler rejects unsafe anywhere 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 is num-bigint and num-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.py runs 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: with is a SyntaxError, nothing reads Symbol.unscopables, direct eval runs as indirect eval, a runtime has one realm, and nothing reads Symbol.species (deviation ledger).
  • Runs where you need it. A qjs command 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.

Install

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-cli

Command line

qjs -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 scriptArgs

The file loader follows QuickJS: .json imports are strict JSON, and with { type: "json5" } selects QuickJS's extended JSON.

Embedding

[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.

Compatibility

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.

Documentation

Development

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:browser

rust-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.

License

MIT. Third-party notices are in NOTICE and LICENSES.

About

An independent Rust rewrite of QuickJS targeting semantic feature parity

Topics

Resources

Stars

81 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages