Server driven UI for SwiftUI
Server driven UI for SwiftUI means your backend describes a page as JSON and the iOS client renders native SwiftUI, not a WebView.
Server driven UI for SwiftUI is a split of labour. The backend describes a page as JSON. The iOS client turns that document into native SwiftUI views. The pixels come from the platform, not from a browser process.
That is the whole idea. Teams reach for it when merchandising, onboarding, or a feed changes faster than App Store review. The binary already knows how to draw a title block, a list row, a banner. The server decides which of those widgets appear, in what order, with what copy.
This article is the long form of that definition. The homepage owns the same phrase for search; this post is the cluster page you send someone who asked "what is server driven UI in SwiftUI?" and stayed for the details.
What server driven UI is#
A page document arrives as data. Flow-UI names the document an envelope: a page id, optional header and footer bars, a list of sections, and widgets inside those sections. Architecture is the map of the types.
The client does four jobs:
- Decode the envelope.
- Look up each widget
typestring in an open registry. - Render a real SwiftUI view for every known type.
- Dispatch taps as declarative actions, not as hardcoded
NavigationLinktrees.
The registry is the product decision. Tutorials on Medium and in gists almost always show a closed enum of widgets with a giant switch. That works until the backend invents a type the enum does not name. An open registry maps a string to a WidgetView. Unknown types drop out of the page instead of failing the decode. Debug builds show a placeholder. Release builds skip. That policy lives on UnknownWidgetPolicy.
Registration is one line. Last registration for a type string wins, so your app can override a starter widget without forking the package.
What it is not#
It is not a WebView. WKWebView renders HTML in a web process. Scrolling, swipe back, Dynamic Type, and VoiceOver behave like a website sitting inside your app. Server driven UI for SwiftUI keeps the view tree in SwiftUI. That distinction is the first thing people argue on Hacker News whenever someone posts "What Is Server-Driven UI?"
It is not Flutter or React Native. Those still ship UI as code. A padding tweak waits on a store release. SDUI ships UI as data on top of a native toolkit you already chose.
It is not remote HTML, and it is not a downloaded script. Guideline 2.5.2 is about executable code you did not ship in the binary. A JSON page that picks among widgets already compiled in is data. A script field that evals is not. Do not treat this paragraph as legal advice. Read Apple's text.
It is not a network library. Flow-UI does not call URLSession. Your app implements PageLoader.loadPage(_:) async throws -> Data. Fixtures, GraphQL, REST, a file on disk: the renderer only sees bytes.
Page, section, widget#
Flow-UI does not have a type named screen or card. The vocabulary is page, section, and widget.
A page is the unit you fetch. It can carry a nav bar, a sticky header, a footer, pagination, and pull to refresh flags.
A section is a layout region: a vertical stack, a carousel, a grid. Sections exist so the backend can mix those regions on one page.
A widget is one native view. Starter widgets cover headings, image plus text rows, banners, buttons, tags, steppers, accordions, and separators. Your product widgets live in your app target and register the same way.
Airbnb's Ghost write-up is the industry pattern, not a Flow-UI case study: one schema, native renderers per platform. iOS draws SwiftUI. Android draws whatever that team owns. The JSON is the contract.
Why iOS teams want it#
App review is the obvious reason. Rearranging widgets that already exist in the binary is a data deploy. New widget types still need a release. That split is honest. If your UI changes once a quarter, a SwiftUI preview and a normal ship cycle may be faster than an SDUI pipeline.
The second reason is old binaries. A user who has not updated still has to render something. Lossy decoding plus an unknown-type policy is how you avoid a blank page when marketing ships promo_v2 and 12% of sessions are on last month's build.
The third reason is specialised surfaces. Feeds, carts, onboarding, help, merchandising: those are the places Jacob Bartlett and the Reddit thread he quotes call useful. A generic "HTML in JSON" framework that tries to replace every canvas is the hubris case. Flow-UI is a Swift package for the useful surfaces, not a replacement for MapKit.
Where Flow-UI sits#
Flow-UI is MIT licensed. The products are FlowCore (envelope, atoms, loader protocol), FlowRender (registry, page view, actions), and FlowWidgets (starter examples you can override). Install the Swift package, implement PageLoader, register widgets, present FlowPageView.
The docs playground lets you paste a page document in the browser. That playground is not the iOS Simulator. It exists so backend and iOS can stare at the same JSON.
What you still ship in the binary#
Every widget type is Swift code. The server cannot invent a gesture recogniser you did not compile. If you need a map, a camera, or a custom chart, that view is a widget you write and register. After that, the backend can place it.
Actions are data: toast, sheet, api, deeplink, dismiss, refresh. Flow-UI does not ship a router. A deeplink action is a payload. Your ActionHandler decides NavigationStack, a tab, or an external URL.
A worked path in one file#
Copy this order in a new app if you are evaluating the package. It is the same order as Quick start.
- Add the Swift package. Products are
FlowUI(umbrella), orFlowCoreplusFlowRenderif you do not want starter widgets. - Create a registry at launch. Call
FlowWidgets.register(on:)thenregistry.register(YourWidget.self). - Implement
PageLoaderagainst an existing client. ReturnData. Do not pre-decode into a private struct. - Construct
PageStore(pageID:loader:registry:)and presentFlowPageView(store:).
That is enough to render the JSON above as a native title. Custom widgets come next, not first.
What the playground is for#
The docs playground renders the same registry idea in the browser so backend and iOS can stare at one document. It is not the Simulator. It is not a substitute for running FlowPageView on a phone. Use it to argue about the envelope, then verify on device.
Who owns the catalogue#
iOS owns Swift types. Backend owns which types appear on a page. Design owns tokens and layout values that fit the atoms. If one of those three starts inventing types in Slack without a registry change, you will ship JSON that old binaries skip and new binaries do not contain either.
Write the type string down. Register it. Then compose.
Search and this URL#
The homepage already targets the phrase server driven UI SwiftUI. This article is the long-form definition in the same cluster. It does not claim a ranking. It exists so a reader who wants the why has a URL that is not a getting-started checklist.
Read next#
- Introduction for the product pitch and install path.
- Architecture for decode, registry, render, dispatch.
- FAQ for WebView, synonyms, and unknown widgets.
Server driven UI for SwiftUI is JSON in, native views out. Keep the definition that small and the rest of the stack stays honest.
Related documentation
Get started
Introduction
Flow-UI is an open source server driven UI framework for SwiftUI. Your backend describes an iOS screen as JSON and Flow-UI renders it as native views.
Concepts
Architecture
How Flow-UI turns a JSON page into native SwiftUI: decode through an open registry, contain failures, render widgets, and dispatch actions as data.
Related articles
- Server-Driven UI5 min read
SDUI vs WebViews on iOS
SDUI renders native SwiftUI from JSON. A WebView renders HTML in a browser process. Teams pick SDUI when the page should feel like the rest of the app.
- Server-Driven UI4 min read
API driven UI and remote UI, explained
API driven UI and remote UI are names for the same idea as server driven UI: the API returns page structure, the iOS app paints SwiftUI.
- Server-Driven UI4 min read
Backend driven UI vs server driven UI
Backend driven UI, server driven UI, BDU, and SDUI are the same split: the server describes the page, the client renders native views.
More on the blog.
Read the source
Flow-UI is MIT licensed. The schema, renderer and starter widgets live on GitHub.
GitHubGet started with Flow-UI
Install the Swift package, register a widget, and render a page from JSON.
Get started