JsonUI
← ConceptsHot reload everywhereOne JSON edit, three simulators update in under a second. On web the React dev server you already run does it — Next.js dev in the default setup, but any dev server that watches your source tree; iOS and Android both run a Dynamic mode that pulls Layout JSON over the network at runtime. Here is how each platform does it.~5 min read
Web: your framework's dev serverWeb is the simplest case: `jui hotload listen` is not a web target at all — the hotload server lists only ios and android as supported platforms, annotated with the note that web is build-step only. A React dev server already does live reload on its own. Start it and edit a Layout JSON: rjui regenerates the TSX as part of your normal `jui build` loop, the dev server sees the changed file under your source tree, and the component in the open tab is hot-module-replaced. No custom runtime, no network fetch, no additional watcher process. Nothing in that loop is Next-specific. Next.js App Router is the default `web_framework` adapter, so `npm run dev` with Fast Refresh is what most projects see — but the toolchain's own web conformance host runs Vite + React with no Next dependency and reloads exactly the same way. Which framework you target is a `web_framework` question, answered in the Web framework adapters guide; hot reload does not change with the answer.
shell
# Next.js dev server — Fast Refresh handles everything.
# No separate watcher or `jui hotload` process is needed for web.
npm run dev
 
# Open http://localhost:3000 and edit docs/screens/layouts/home.json.
# rjui regenerates TSX as part of your normal `jui build` / `jui build --web-only`
# loop, and Next.js picks up the TSX diff via HMR without losing ViewModel state.
iOS: SwiftJsonUI Dynamic modeThe iOS app, when built with Dynamic mode enabled, does not bake the Layout JSON into the binary. Instead it fetches the JSON from a `jui hotload listen` server on the author's machine at screen-mount time and subscribes to WebSocket push notifications for subsequent edits. When the server detects a change under `docs/screens/layouts/`, it resolves style includes + applies iOS-specific filtering and pushes the flat JSON over `ws://host:8081/ws`; the simulator picks up the change and re-renders without a rebuild. Release builds flip Dynamic mode off and revert to compiled SwiftUI, so production is unaffected.
MyApp.swift
// MyApp.swift — enable Dynamic mode in DEBUG. The HotLoader endpoint is
// read from `hotloader.json` (Bundle or Documents) which `jui build`
// writes from docs/hotload/config.json — no URL parameter needed here.
import SwiftJsonUI
 
@main
struct MyApp: App {
init() {
#if DEBUG
HotLoader.instance.isHotLoadEnabled = true
ViewSwitcher.setDynamicMode(true)
#endif
}
var body: some Scene { WindowGroup { ContentView() } }
}
shell
# Start the unified hot-reload server alongside Xcode.
# One process serves both iOS and Android simultaneously;
# you only start it once per workspace.
jui hotload listen
 
# Expected output:
# 👀 Watching docs/screens/layouts/...
# 📡 HTTP: /ios/layout/* | /android/layout/*
# 📡 WS: /ws (platform declared via handshake)
# 📡 Listening on ws://0.0.0.0:8081
# ✅ ios connected
Android: KotlinJsonUI Dynamic modeAndroid works through the *same* `jui hotload listen` process the iOS tab describes — one server serves both platforms, distinguishing them via a WebSocket handshake (`{ platform: 'android' }`) and per-path HTTP routes (`/android/layout/*`). The app's Dynamic mode runtime fetches on screen mount, subscribes to layout_changed events, and lets Compose re-run its declarative pipeline with the new spec. The Compose runtime's incremental re-render machinery does the rest — swapping a single Label's text takes a single recomposition, not a full screen teardown.
MyApplication.kt
// MyApplication.kt — initialize KotlinJsonUI; Dynamic mode auto-enables for debug builds.
import android.app.Application
import com.kotlinjsonui.core.KotlinJsonUI
 
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
KotlinJsonUI.initialize(this)
}
}
shell
# The same `jui hotload listen` from the iOS tab also serves Android —
# you don't need a second listener. If it's not running yet:
jui hotload listen
 
# Emulators reach the host via 10.0.2.2 (default config).
# Physical devices need your LAN IP, e.g.:
# ws://192.168.x.x:8081/ws
# Set `client.ip` in docs/hotload/config.json accordingly.
Why it mattersHot reload is the feedback loop. Shortening it turns design iteration from 'edit → build → wait → click through to the screen → check' into 'edit → see'. Multiplied across every design decision on every screen on every platform, it compounds into a multi-order-of-magnitude difference in how much design can be explored per hour of engineering time. It is why front-end web work has felt so different from native for the last decade; JsonUI brings the web-style loop to the two platforms that most need it.
Keep reading
ViewModel-owned stateThe discipline that keeps hot reload safe even when state is involved./concepts/viewmodel-owned-state
Why spec-firstReturn to the contract that makes all the other pieces consistent./concepts/why-spec-first