Skip to content

Choosing a Runtime

xript ships four runtime implementations, all conforming to the same specification. A script written for one runs identically on the others; the manifest schema, capability model, and security guarantees are shared across every one of them.

UniversalNode.jsRustC#
Package@xriptjs/runtime@xriptjs/runtime-nodexript-runtimeXript.Runtime
SandboxQuickJS WASMNode.js vmQuickJS (native)Jint (pure C#)
EnvironmentsBrowser, Node, Deno, Bun, WorkersNode.js onlyAny Rust appAny .NET app
Manifest loadingPass object directlycreateRuntimeFromFilecreate_runtime (JSON)XriptRuntime.Create (JSON)
Async bindingsVia initXriptAsync()Native async/awaitadd_async_function (script awaits a Promise)Sync only (Jint)
Memory isolationSeparate WASM heapShared Node.js processSeparate QuickJS heapJint engine per runtime
Best forCross-platform, browserNode.js servers, CLIRust apps, game enginesUnity, Godot (.NET), enterprise

Every runtime enforces the same security model regardless of the host language or sandbox technology:

  • No sandbox escape. Scripts cannot access the host filesystem, network, or process. Only bindings declared in the manifest are reachable.
  • No denial of service. Execution limits (timeout_ms, memory_mb, max_stack_depth) prevent runaway scripts from consuming unbounded resources.
  • No implicit trust. Capabilities are opt-in and default to empty. A script cannot call a capability-gated binding unless the host explicitly grants that capability.
  • No eval. eval(), new Function(), and dynamic code generation are blocked at the engine level across all four runtimes.

For the full security specification, see Security.

All four runtimes consume the same xript.manifest.json schema. A manifest written for one runtime needs zero changes to run on another; the bindings, capabilities, hooks, types, and limits are all portable.

For the manifest specification, see Manifest.

Beyond the manifest schema, every runtime implements the same extensibility and lifecycle surfaces, verified against a shared contract:

  • Cooperative cancellation and per-capability audit. A cancellation token interrupts in-flight execution (QuickJS, rquickjs, and Jint mid-run; Node’s vm checks at execute/invoke entry), and an opt-in audit channel reports every allowed binding invocation.
  • Manifest inheritance (extends). A manifest can extend one or more bases; add-new names, fill abstract: true holes, and refines: true deep-merges, all resolved identically across the four runtimes before validation.
  • The fills contribution model. A host declares typed slots and a mod fills them through a single fills object keyed by host slot id; fragments, provider roles, and lifecycle-hook handlers are all fills of typed slots. (Legacy fragments[] and contributions still load but emit a deprecation warning.)
  • Host-invoke exports and real ES modules. entry.format: "module" evaluates a mod entry as an ES module, and top-level named exports auto-register as host-invokable. External imports stay denied.
  • DAP-shaped debugging. Each runtime drives a Debug Adapter Protocol–shaped debug session: set/clear breakpoints, pause/resume/step, inspect scopes and frames, with per-engine fidelity documented rather than papered over.
  • JS/WASM Runtime — universal sandbox, runs anywhere JavaScript runs
  • Node.js Runtime — optimized for Node.js with file-based manifest loading
  • Rust Runtime — native QuickJS sandbox for Rust host applications
  • C# Runtime — Jint sandbox for .NET, Unity, and Godot applications