I like to build … Desktop & mobile apps#
Take a full-stack Jac app and wrap it in a native shell -- a desktop window that embeds the OS webview, an Android/iOS webview build, or (for platform-native views) a React Native build. These map to the desktop and mobile project kinds and the mobui client kind.
Status: beta 🧪
The desktop binary renders your cl UI and runs sv walkers/functions in-process on the embedded interpreter (shipped), with full HMR dev mode via jac start --client desktop --dev. Only per-OS installers/code-signing remain open (issue #6436). Both mobile paths are frontend-only -- the app talks to a Jac server you deploy separately. Everything else on this page works as shown.
Your 5-minute quick win#
Start from any full-stack app. Jac compiles your cl UI into one jac nacompiled binary that embeds the OS webview (WebKitGTK / WKWebView / WebView2) -- no Rust toolchain, no PyInstaller, no separate process. The desktop target ships with jaclang core:
jac build --client desktop # → .jac/client/desktop/<app> (single binary)
jac start --client desktop # build + launch the native window
jac start --client desktop --dev # HMR: Vite serves cl on 127.0.0.1, recompiles on .jac saves
In dev mode the native host is built once, then your cl UI is served from
Vite on loopback and recompiled on every .jac save -- the desktop window
hot-reloads just like jac start --dev does for web. Walker/function calls
still go through the embedded in-process runtime, so RPC works identically
to the packaged build.
Window title and size are configured under [desktop] in jac.toml. On Linux you need the WebKitGTK system libraries (a bundled helper script installs them).
Ship to Android & iOS#
Ship the same client bundle to mobile via Capacitor, which wraps it in a native webview. The mobile app is the frontend only -- it talks to your Jac server over HTTP, so deploy the backend separately (e.g. as a backend service):
# prerequisites: Android: JDK + Android SDK; iOS (macOS): Xcode (no Node.js -- JS tooling runs on the bundled Bun)
jac setup mobile --platform android # one-time scaffold
jac start main.jac --client mobile --dev # live reload on device/emulator
jac build --client mobile --platform android # → app-debug.apk
Use --platform ios on macOS to produce an Xcode project. App name and id are set under [client.mobile].
Ship platform-native views (React Native)#
For true native views instead of a webview, the React Native target compiles your cl UI to platform-native components via Expo/Metro. Author the UI once in the portable @jac/mobui vocabulary (View, Text, Pressable, ...) and the same source also runs on the web -- set client_kind = "mobui" under [project] and raw HTML tags become compile errors (E1105) so the tree stays portable:
# prerequisites: Android: JDK + Android SDK; iOS (macOS): Xcode (no Node.js -- JS tooling runs on the bundled Bun)
jac setup react-native # one-time Expo scaffold (.jac/mobile-rn/)
jac start main.jac --client react-native --dev # Metro Fast Refresh on device/emulator
jac build --client react-native --platform android # → APK (iOS: .app via xcodebuild, .ipa via EAS)
Start from examples/mobui/hello; examples/mobui/littlex shows the full-stack picture including .native.cl.jac platform-split modules.
Your learning path#
- Concepts you need → Core Concepts -- the client codespace
- Build the app first → Full-stack web apps (a desktop/mobile app is a full-stack app plus a shell)
- Build it for real → Desktop App · Mobile App (covers both Capacitor and React Native)
- Look it up → jac-desktop reference · jac-client reference (React Native target)
Going further#
- Add AI features → AI agents & LLM apps
- Scale the backend your app talks to → Backend APIs & services