FAQ

Straight answers about what bext-lite is, what runs today, and how it compares to the alternatives. Some targets are further along than others, and this page says which.

Is bext-lite production ready? What is the status?#

The native binary target (bext-lite serve) is shipped and is what you run today: a v8-free host that renders real data-driven PRISM apps - pages, API routes, and KV, per-app DB, fs, queue, and cache - from a few megabytes. The AOT exporter, byte-faithful QuickJS render, the warm-context render pool, two-tier OTA, and the desktop embedding are all built and tested end to end.

For mobile, the pure-Rust and JS substrate is built and CI-tested on the host: the native bridge, the inbound-event ring, the device/-only HTTP boundary, and the bext-lite mobile CLI plus a Tauri shell template. What still needs a Mac or an Android NDK is the device cross-compile confirmation, the real Swift and Kotlin device implementations, and store packaging. Desktop GUI packaging needs webkit2gtk, and the edge and browser (WASM) targets need a Javy toolchain.

So: the runtime and exporter are solid and demonstrated; some target packaging is toolchain-gated. Treat it as a working runtime with target packaging in progress, not a tagged 1.0.

How big is it?#

The v8-free host binary is 1.8 MB. Your app - route and API bundles plus static assets - is a couple more megabytes, so the whole thing ships in about 4 MB and starts instantly. The data-capable build (bundled SQLite for KV and the per-app DB, pure-Rust rustls TLS for external fetch and OTA) is about 6 MB. Compare Electron at 150 MB or more.

Does it need Node or V8?#

No. There is no Node runtime, no V8 pointer cage, and no install step on the target. The exporter compiles your app to plain JavaScript ahead of time, and the runtime evaluates it with QuickJS (or with V8 where you have the room). You do need a build-time toolchain to export "use client" React pages (bun plus a vendored react / react-dom / scheduler); string-builder-only apps need neither. See The engine decision.

Which engine runs my app, and why QuickJS on iOS?#

It is per-target. V8 runs on desktop and the single-binary server (it already works, the React snapshot is proven, and the footprint is fine there). QuickJS runs everywhere else: mobile, edge, browser, and embedded. Two hard external facts force the split:

  • iOS bans JIT for third-party apps. QuickJS is a pure interpreter with no JIT, so it is App Store legal by construction. A JIT engine like V8 cannot run inside a third-party iOS app.
  • You cannot embed V8 in a WASM module. Edge and browser targets are either someone else's engine you do not control, or WASM where only an interpreter fits.

A compiled PRISM bundle plus 122 KB of pure-JS polyfills runs unchanged on both engines, and the output is byte-identical. See The engine decision.

Will it pass App Store review?#

The mobile app is a WebView with bundled content plus a jitless QuickJS interpreter for glue - the same category as Capacitor and Ionic, which is squarely accepted. QuickJS being jitless is the key: no downloaded executable code and no JIT.

OTA content updates must respect App Store Guideline 2.5.2 - hot-swap content and bug fixes, but do not ship an update that adds a feature the reviewed binary could not do. Native runtime changes go through the store as a normal release. The build-time-render model is the most review-friendly; on-device SSR is still legal but reviewed more strictly. Honest caveat: no app has been through review yet, since the device build needs a Mac. See Mobile and OTA updates.

Does it work offline?#

Yes. KV, a per-app database, and object storage are self-contained SQLite that ships in the app bundle and is copied to a writable data dir on first launch. Reads and writes are local: no network, no server, works offline. You can optionally sync to a remote bext later. The browser target is offline-first through a service worker with local SQLite (WASM). See Data and storage.

Can I use React?#

Yes. "use client" React pages AOT-compile to a real React SSR bundle (ReactDOMServer.renderToString), which renders correctly on both V8 and QuickJS - React and ReactDOMServer are pure JS, and React 19 SSR was verified under QuickJS with props threaded and useState state intact. For lighter interactivity you can use signals islands, which hydrate without a full React runtime. Suspense streaming SSR is disabled on lite (pages render buffered, then serve), which is correct for a single-tenant app. See React and The engine decision.

How is it different from Electron, Capacitor, React Native, or NativePHP?#

  • Electron bundles a full Chromium and Node (150 MB or more). bext-lite uses the OS WebView plus a 4 to 6 MB host, so a desktop app is roughly 10 to 20 MB - about 10x smaller - and the same source also targets edge, mobile, browser, and ARM.
  • Capacitor / Cordova share the shape (OS WebView plus a native bridge) but wrap a client-only web app. bext-lite additionally runs your PRISM SSR (string-builder or React) at build or on-device, with a self-contained server-side data layer, and the same bundle can also deploy as a server or an edge function.
  • React Native renders to native views through a JS bridge, and you write to its component model. bext-lite renders your normal web UI in a WebView, so you keep your existing PRISM and React code and reach native APIs through bext.device.*.
  • NativePHP is the closest analog in shape - an on-device interpreter, a WebView, and a native bridge. The difference is runtime pain: NativePHP had to build a jitless PHP for iOS, whereas QuickJS is jitless by construction, so the single hardest constraint was engineered around on day one.

See Deploy targets and Mobile.

Can I use my existing PRISM app unchanged?#

Mostly. The exporter compiles the same routes, API handlers, actions, and islands the multi-tenant server does, and the output is byte-identical (sha256-verified) - point bext-lite-build at any PRISM site source. Run bext-lite check to render every route once under QuickJS and confirm the app is lite-eligible before you publish; it flags anything that leans on the multi-tenant platform (the WAF, TLS termination, cross-tenant features) or on dynamic eval. bext-lite is single-tenant by design: no multi-tenancy, no WAF, no TLS by default. Your app's own signed-cookie auth works; masquerade-coupled platform sessions do not. See Quickstart and Architecture.

How do updates work?#

Two tiers. Tier 1 content OTA hot-swaps the signed dist-lite/ payload - routes, API, UI, and logic - with no native binary change and no app-store review. Bundles are ed25519-signed, extracted and verified before an atomic swap, and applied with no restart (in-flight requests finish on the old bundle). One mechanism serves both desktop and mobile. Tier 2 native shell OTA updates the binary itself (Tauri's signed updater on desktop, an app-store update on mobile) and is used only when the native layer changes. A bundle can declare a minimum runtime version, so a content update never lands on a runtime too old to run it. See OTA updates.

Is my data secure?#

On-device data lives in a writable data dir outside the swappable bundle, so an OTA cannot wipe it. The security boundary matters most: only the device/ namespace is reachable over HTTP, while the data SDK (kv, db, fs, queue, cache, secrets) stays in-process-only. A direct POST /__bext/sdk/kv/get from a client returns 404 by design, so when bext-lite runs as a public-proxied tenant no visitor can read another tenant's data. Your client-side data access goes through your app's own /api/* routes, which touch the SDK server-side. OTA bundles are ed25519-signed and refused if they do not verify, and secure device storage uses the OS Keychain or Keystore. See Security and Data and storage.