Safe Rust · JavaScript engine

QuickJSOxide

An embeddable JavaScript engine for Rust applications, written in safe Rust. Zero lines of unsafe, from the parser to the garbage collector.

OXIDE · FRACTAL LAB
Computing
0%engine 0.00 s0 iterations

Computed by quickjs-oxide WASM. The browser host draws.

Build info
engine
loading…
commit
…
engine load
…
view
whole set, −0.75 + 0i, width 3.3
image
…
host
Web Worker + canvas

Why oxide

0 unsafe

Safe Rust

Every crate in the workspace sets forbid(unsafe_code): the engine, the CLI and the WebAssembly bindings.

≈1× QuickJS

QuickJS-class speed

Register bytecode, inline caches and NaN-boxed values keep run time level with QuickJS on the V8 v7, Octane and Are-We-Fast-Yet suites.

Native + WASM

Runs where you need it

Embed it in a Rust application, use the native qjs command line, or ship the WebAssembly build to the browser, like the demo above.

By the numbers

Measured against QuickJS 2026-06-04, the engine quickjs-oxide follows. Method and raw results are in the docs.

97.46%
Test262 pass rate

81,441 of 83,562 variants in the scope QuickJS runs.

≈1×
QuickJS speed

Geometric mean of run time relative to QuickJS. Lower is faster.

V8 v7 0.94×Octane 1.15×AWFY 0.99×
0
Lines of unsafe

The compiler rejects unsafe in every crate of the workspace.

0
Dependencies

No third-party crates, except num-bigint for BigInt. The native host adds tz-rs for time zones.

Release builds on one Linux machine. See the method and every result →

Start here

Add the two crates, create a runtime, evaluate a script and read the result.

Cargo.toml
[dependencies]
quickjs-oxide = { git = "https://github.com/pocket-nexus/quickjs-oxide" }
quickjs-oxide-host = { git = "https://github.com/pocket-nexus/quickjs-oxide" }
src/main.rs
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 mut 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(())
}