Native (mobile)
miso native
Your program runs in two JS interpreters at once: the main thread (MTS), which owns the drawing facilities, and the background thread (BTS), which owns the native modules. miso runs on both and keeps them in sync. See the dual-thread architecture.
Miso.Native targets native mobile devices by driving the Lynx runtime instead of the browser DOM. The same MVU programming model, Component API, event delegation, and virtual-DOM diffing carry over unchanged from the web; only the element vocabulary differs (view_ and text_ instead of div_ and span_), and rendering goes through Lynx's element PAPI instead of a browser DOM.
This module is the native analogue of the miso / startApp entry points: native (and nativeWithContext) boot a root component onto the Lynx runtime.
Anatomy of a native miso app
Keep scrolling and the phone comes apart into the dual-thread architecture that runs miso on iOS and Android.
A miso app on your phone.
It all lives in one iOS process.
Lynx hosts two JavaScript interpreters: the main thread renders, the background thread thinks.
Each interpreter loads the same bundle: JavaScript, CSS, assets.
And inside the JS: two GHC runtimes, one application, one miso.
Enabling native
The native backend is gated behind the native cabal flag. It must be enabled to bring Miso.Native and the Miso.Native.* element / event / FFI modules into scope (build with -fnative). Web / WASM builds are unaffected — all cross-thread machinery lives behind the NATIVE CPP guard.
$ nix develop github:dmjio/miso#native
$ cabal build -f native \
--with-compiler=javascript-unknown-ghcjs-ghc \
--with-hc-pkg=javascript-unknown-ghcjs-ghc-pkg
The JavaScript output is bundled for Lynx with rspeedy and loaded by the Lynx Explorer app or your own iOS / Android shell. The miso-lynx repository has the tooling, and miso-lynx-gallery a gallery of native components.
Building a bundle with Nix
miso's flake exports everything needed to produce a main.lynx.bundle reproducibly. miso.lib.${system}.ghcNative is the GHC-JS package set with miso-native preinstalled — callCabal2nix your own app into it — and pkgs.mkLynxBundle (also exported as miso.lib.${system}.mkLynxBundle) turns that JS derivation into a Lynx bundle:
{
inputs.miso.url = "github:dmjio/miso";
outputs = { miso, ... }:
let system = "x86_64-linux";
# or aarch64-darwin, …
lib = miso.lib.${system};
in {
packages.${system}.bundle = lib.mkLynxBundle {
name = "my-app-bundle";
jsDrv =
lib.ghcNative.callCabal2nix "my-app" ./. { };
exeName = "my-app";
styles = ./styles.css;
};
};
}nix build .#bundle then leaves result/main.lynx.bundle ready to load in the Lynx Explorer app. For interactive work, nix develop github:dmjio/miso#native provides the GHC-JS compiler (the ghcNative package set), rspeedy and bun.
To ship a standalone iOS app, the miso-lynx-gallery example includes an ios/ folder: copy the bundle the Nix derivation produced (the /nix/store output symlinked at ./result) into the assets in ios/ and build with Xcode. See miso-lynx-gallery for more information.
Gallery
The UI stack miso drives natively, in the flesh — screens from Lynx's example apps. The miso-lynx-gallery repository builds a gallery of these components in miso.



In this section
- The dual-thread architecture — BTS vs MTS, what crosses the boundary, the instant first frame.
- Static mounting — why constructors cross threads as static pointers.
- Effects, subscriptions and threads —
runOnBG,runOnMainand guarding subs. - Main-thread events — low-latency
*Mainhandlers. - Main-thread-local state —
MainThreadRefandeachFrame. - Platform APIs — which APIs exist on which thread.
- A minimal native component — the counter, natively.