CONCEPT Cited by 2 sources
Server-driven UI¶
Definition¶
Server-driven UI (SDUI) is the architectural choice to
have the server describe, per request, the UI the client
should render — the structure (views, layouts, sections), the
content (components with their parameters), and the behaviour
(actions tied to events like onClick / onView). The client
is a renderer of server-authored configurations; it does not
own the layout or the content graph.
Compare with client-driven UI, where layout, copy, and navigation are baked into the client binary / bundle, and the server returns only data.
Why organisations adopt SDUI¶
- Decouple UI release from app release. New screens, content changes, and experiments ship without an app-store submission or web deploy — subject to the client already supporting the underlying components and actions.
- One design language across platforms. iOS, Android, and web render from the same CHAOS/SDUI configuration (modulo platform-specific layouts), so there's one source of truth for screen composition.
- Fast A/B and personalisation. Server can vary the configuration per user / cohort / request with no client work per experiment.
What the server has to describe¶
At minimum, every SDUI system defines four shapes (names vary):
- View — a logical screen, addressable by an ID.
- Layout — how sections on a view are arranged (single-column, multi-column, mobile toolbar+footer, …).
- Components — leaf UI elements (text, button, illustration, list row, …) with typed parameters.
- Actions — behaviours attached to components (open URL, navigate to subsequent view, log event, …).
Yelp's CHAOS adds two advanced primitives on top — View Flows (bundled preloaded subsequent views) and View Placeholders (nested async-loaded views) — covered in sources/2025-07-08-yelp-exploring-chaos-building-a-backend-for-server-driven-ui.
Hard constraints SDUI systems must solve¶
- Mixed client-version fleet. Old app versions don't support new components. The server must know what each client can render and skip / substitute accordingly — see concepts/register-based-client-capability-matching for feature-level gating, and concepts/client-spec-version + concepts/component-version-migrate-function for component-version-level backward compatibility (Yelp CHAOS uses both).
- Schema stability vs element iteration. Adding a new component type ideally doesn't require a GraphQL / REST schema change. CHAOS's answer is JSON-string parameters under a stable schema.
- Cross-platform consistency of the component vocabulary. Every platform must deserialise the server-authored UI into the same conceptual shape. Yelp's answer is Konbini — codegen of four language-specific libraries from one JSON interface definition per component. See patterns/single-json-spec-to-multi-platform-codegen.
- Per-feature fault isolation. One bad feature must not break the whole view. CHAOS wraps every FeatureProvider in an error decorator — see patterns/error-isolation-per-feature-wrapper.
- Parallel async data loading. Each feature typically has its own data dependencies; the server must fan out upstream calls in parallel — see patterns/two-loop-parallel-async-build.
Known SDUI implementations¶
- Yelp CHAOS (canonical on-wiki) — GraphQL-fronted, multi-backend, Python Strawberry subgraph. Web + iOS + Android + Python. Paired with Konbini + Cookbook for cross-platform codegen.
- Zalando Appcraft (on-wiki) — mobile-native-only SDUI. Elm architecture on the client, Flex on top of Texture / Litho, narrow primitive vocabulary, full server-owned versioning, 6 years in production. Replaced 2016-era TNA (Composed Tiles) which had collapsed under client-bound UI variants. Serves 13 dynamic pages including Zalando Stories (2024).
- Airbnb Ghost Platform (not on wiki) — the widely-cited SDUI precedent.
- Lyft Server-Driven UI (not on wiki) — similar shape at ride-hailing scale.
- Meta Shops / Facebook Marketplace use SDUI-like internal frameworks (not publicly detailed).
Design axes observed across implementations¶
Three orthogonal axes (instances given for each):
| Axis | CHAOS | Appcraft |
|---|---|---|
| Wire format | GraphQL + JSON-string component params | Component-tree JSON |
| Cross-platform unit | Per-component codegen (Konbini) | Shared Flex spec |
| Version negotiation | Client reports spec version | Server-owned; client reports only app version |
| Client UI substrate | Native + web DOM | Texture / Litho on top of UIKit / RecyclerView |
| Client programming model | Platform-native | Elm architecture |
Seen in¶
- sources/2025-07-08-yelp-exploring-chaos-building-a-backend-for-server-driven-ui — first wiki instance; CHAOS backend deep-dive.
- sources/2026-04-22-yelp-how-yelp-keeps-server-driven-ui-consistent-across-four-platforms
— follow-up on Konbini + Cookbook, the cross-platform
codegen layer beneath CHAOS; single JSON interface
definition → four platform libraries; spec-version
negotiation +
migrate()functions for backward compatibility. - — Zalando Appcraft 6-year retrospective: predecessor TNA (Composed Tiles) failed because small UI changes forced client releases; Appcraft replaced it with Elm + Flex + narrow primitive vocabulary + server-owned schema versioning + deep-link indirection. Canonicalises the release-boundary rule ("a client-release is only required when there's a need to introduce a new primitive or extend the contract of an existing one") and concepts/same-day-ui-delivery as the resulting cadence property.
Related¶
- systems/yelp-chaos
- systems/yelp-konbini
- systems/yelp-cookbook
- systems/zalando-appcraft
- systems/zalando-truly-native-apps-tna
- concepts/json-string-parameters-for-schema-stability
- concepts/register-based-client-capability-matching
- concepts/client-spec-version
- concepts/component-version-migrate-function
- concepts/elm-architecture
- concepts/flexbox-as-cross-platform-layout-primitive
- concepts/ui-primitives-as-platform-building-blocks
- concepts/server-owned-schema-versioning
- concepts/client-release-needed-only-for-new-primitives
- concepts/same-day-ui-delivery
- concepts/deep-link-to-screen-config-resolution
- concepts/appcraft-interoperability
- patterns/error-isolation-per-feature-wrapper
- patterns/two-loop-parallel-async-build
- patterns/view-placeholder-async-embed
- patterns/preloaded-view-flow-for-predictable-navigation
- patterns/single-json-spec-to-multi-platform-codegen
- patterns/spec-version-negotiation-for-backward-compat
- patterns/migrate-function-for-component-downgrade
- patterns/flex-on-top-of-native-ui-framework
- patterns/deep-link-indirection-middleware
- patterns/demo-harness-for-sdui-rendering
- patterns/pr-deployed-renderer-testing-in-debug-app