Quickstart
From zero to a running PRISM app in two commands: export, then serve. This
guide uses the repo's runnable demo, device-playground, which exercises the
whole stack (string-builder pages, a React page, on-device data, and the native
device SDK) so you see a real app, not a toy.
If you have not built the binaries yet, do Installation
first. The commands below assume bext-lite-build and bext-lite are on your
PATH and that you are at the root of the bext monorepo.
1. Export the app to dist-lite#
The exporter compiles every route into a self-contained bundle directory. The
device-playground app has "use client" React routes, so the exporter runs a
real React SSR build. Point it at the vendored React and the shared framework:
BEXT_LITE_VENDOR_NODE_MODULES="$PWD/vendor/node_modules" \
BEXT_SHARED_FRAMEWORK_DIR="$PWD/sites/shared/framework" \
bext-lite-build crates/bext-lite/examples/device-playground -o /tmp/dp
You will see each route compile, then a summary:
bext-lite-build
site: .../device-playground
output: /tmp/dp
routes: N discovered
...
===== bext-lite-build done =====
manifest: /tmp/dp/manifest.json
The /tmp/dp directory now holds everything the app needs:
dist-lite/
manifest.json route table (url, key, bundle, params, isDynamic, ...)
routes/<key>.js page bundles (define __bextPrismRender)
api/<key>.js api bundles (define __bextApiHandler)
actions/<stem>.js server-action bundles
islands/<name>.js compiled client / signals islands
react-base.js the shared React runtime (only if the app has React pages)
public/ copied static assets
A string-builder-only PRISM app (no "use client" React pages) needs neither the
BEXT_LITE_VENDOR_NODE_MODULES nor BEXT_SHARED_FRAMEWORK_DIR variable, and no
bun. For those, the export is just bext-lite-build ./app -o ./dist.
2. Serve it#
bext-lite serve /tmp/dp --port 8080
The runtime loads the manifest into an in-memory route table, then serves over a small hand-rolled HTTP/1.1 server. Pages render on QuickJS. The first hit to a route is a cold render (about 9 ms); after that the warm-context pool renders it in about 1 ms.
3. Open it#
Point a browser at http://127.0.0.1:8080/, or curl the routes:
curl -s http://127.0.0.1:8080/ # overview page (full HTML)
curl -s "http://127.0.0.1:8080/interactive?start=42" # React SSR, renders 42
curl -s http://127.0.0.1:8080/api/notes # [] (on-device KV, empty)
curl -s -X POST http://127.0.0.1:8080/api/notes \
-H 'content-type: application/json' -d '{"text":"hello"}' # add a note
curl -s http://127.0.0.1:8080/api/notes # now lists the note
The /api/notes route reads and writes on-device KV (SQLite), so the note
survives across requests. This is the offline-first data path: no network, no
external database.
The /device page shows the native device SDK. Served headless like this, every
/__bext/sdk/device/* call returns ok:false, status:501 because no native
bridge is installed. Inside a mobile shell those same calls return real camera,
Face ID and GPS results. The app source does not change; only the runtime
underneath it does.
4. Check it before you ship#
bext-lite check renders every route once under QuickJS and runs a static policy
scan, then tells you whether the app is publishable:
bext-lite check /tmp/dp
A clean run ends with => PUBLISHABLE (lite-eligible + policy-clean). A route
that errors on QuickJS, or code that uses dynamic eval, fails the gate with a
non-zero exit so you catch it before publishing.
A taste of another target: mobile#
The same dist-lite/ is what a mobile app ships. Scaffold the shell projects:
bext-lite mobile init # scaffolds ios/ and android/ shell projects
Then build and run on a simulator or device:
bext-lite mobile run ios --dist /tmp/dp
On a machine without the platform toolchain (no Xcode, or no Android SDK/NDK),
mobile run stops cleanly at a toolchain guard that prints exactly what is
missing and how to install it, and exits non-zero. On a Mac with Xcode (or a box
with the Android SDK + NDK), it exports, bundles dist-lite/ into the app, builds,
and launches. The shell boots the same embedded bext-lite server and points a
native WebView at it. See CLI Reference for the full
mobile command family.
What you just did#
- Compiled a PRISM app to a portable
dist-lite/bundle with one command. - Served it from a v8-free runtime with real SSR, a React page, an API route and on-device data.
- Saw the exact bundle that a desktop or mobile build would ship.
Read the CLI Reference next for pack (single-file
distribution), publish and the OTA update flow, and the rest of the commands.