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
Note

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.

Tip

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.