What Server-Driven UI Actually Means
"Server-driven UI" gets used loosely enough that it's worth drawing the actual boundary before anything else: it's an architecture where the backend sends a structured description of a screen — which components appear, in what order, with what data, and what happens when a user taps one of them — and the client renders that description using native components that already shipped and passed review inside the app binary. The server controls structure; the client still owns every pixel of how a given component actually renders.
That's a meaningfully bigger scope than the two patterns it's most often confused with. A feature flag or remote-config value (Firebase Remote Config, LaunchDarkly, Statsig, Split) toggles behavior or content the client already anticipated at build time — show variant A or B, flip a threshold. It cannot introduce a screen composition the client hasn't already coded. And an over-the-air code push (CodePush-style JavaScript patching) goes the other direction: it ships new executable logic, not just structural data, which puts it on the wrong side of a specific Apple App Store rule covered later in this guide.
| Pattern | What Actually Happens | Examples | Strength | Weakness |
|---|---|---|---|---|
| Client-driven UI | Layout and component tree are hardcoded in the app binary at build time. | Requires an app store release for any structural change | Maximum performance and offline reliability; zero server dependency | Every layout change, no matter how small, waits on both platforms' app store review |
| Feature flag / remote config | A server-side value toggles behavior or content the client already anticipates. | Firebase Remote Config, LaunchDarkly, Statsig, Split | Simple, low-risk, easy to test and roll back | Can't introduce a genuinely new component or screen composition the client hasn't pre-built |
| Server-driven UI (SDUI) | The server sends a structured description of components, order, and data; the client renders it with a pre-shipped native registry. | Airbnb Ghost Platform, Lyft Canvas, Yelp CHAOS, DivKit | New screen compositions and section reordering without a client release | Real versioning, testing and security obligations covered later in this guide |
| OTA code push (e.g., CodePush-style) | The server ships new executable JavaScript that a runtime inside the app then runs. | React Native CodePush, Expo OTA updates | Can patch actual logic bugs, not just layout, without a release | Genuinely executes new code post-review — the exact behavior Apple's Guideline 2.5.2 targets |
How It Works: Schemas, Registries, and Renderers
Every production SDUI system, regardless of vendor or in-house build, is built from the same three pieces working together. The component registry is the closed, versioned list of native components the server is allowed to reference — a card, a carousel, a button, a text block — each one already implemented, tested and shipped in the client binary. The schema is the wire format (commonly JSON, protobuf, or a GraphQL response shape) the server uses to describe a specific screen as an arrangement of registry components plus their data. The renderer is client-side code that walks the schema and produces the actual native UI tree — the one piece of genuinely new client work most teams underestimate, because it has to handle every valid schema shape the registry allows, not just the ones a designer mocked up first.
The choice of wire format is not cosmetic. Lyft's Canvas system, covered in its own section below, chose Protocol Buffers specifically for compact binary payloads and field-level backward/forward compatibility at the scale of a ride-hailing app's traffic; Yelp's CHAOS instead built on GraphQL, trading some payload efficiency for a query language its many internal teams already knew. Neither choice is universally correct — it depends on your traffic volume, your team's existing tooling, and how much you value strict schema evolution guarantees versus query flexibility.
The one architectural decision that determines everything downstream
Whether your component registry is closed(a fixed, reviewed list the server can only reference, never extend at runtime) or effectively open (a schema expressive enough to describe arbitrary new behavior). Every system covered in this guide that's still in production — Ghost Platform, Canvas, CHAOS, DivKit — keeps that registry closed. The security section below explains why an open registry is the pattern's actual failure mode, not a more flexible version of the same idea.
Airbnb's Ghost Platform: The Reference Architecture
Airbnb published the most detailed public account of a production SDUI system in a 2021 Airbnb Tech Blog post by engineer Ryan Brooks, describing what Airbnb calls the Ghost Platform (GP) — named for "Guest" and "Host," the two sides of Airbnb's marketplace. GP is described as routing the majority of Airbnb's most-used surfaces — search, listing pages, and checkout — through a single, server-driven data model shared across web, iOS and Android, with native frameworks provided in each client's own language: TypeScript for web, Swift for iOS, Kotlin for Android.
What makes GP the reference architecture other teams' write-ups get compared against isn't just its scale — it's that Airbnb's account explicitly separates the UI-description layer from the data layer underneath it. GP sits on top of a shared data-service mesh Airbnb calls Viaduct, which means the same backend response can carry both "render a carousel here" and the actual listing data that carousel needs, from services that were built independently of the UI layer itself. That separation — UI structure as one concern, data-fetching as another the UI layer merely consumes — recurs in Lyft's and Yelp's systems too, and is worth treating as a design requirement rather than an Airbnb-specific detail.
Ghost Platform itself is not public or open source — there is no SDK you can install. Its value here is as a worked example of scope: Airbnb didn't build GP for one screen or one experiment type, it built a platform team and shared infrastructure around the pattern, which is also why it's the most expensive version of this architecture to replicate and the least appropriate starting point for a team evaluating whether SDUI is worth adopting at all.
Lyft's Canvas, and the Number We Won't Repeat
Lyft's Bikes and Scooters team built its own SDUI layer, called Canvas, documented in a Lyft Engineering blog post by Alex Hartwell. Canvas runs on Protocol Buffers over gRPC — a deliberate choice for a system serving a high-volume, latency-sensitive product, since protobuf's compact binary encoding and numbered-field versioning give the team a documented compatibility story as the schema evolves, something a looser JSON-over-REST design has to build separately.
The other detail worth adopting directly from Lyft's account is naming discipline: Canvas components are named after the product concept they represent — RideOptionCard, PromoBanner, VehicleStatusHeader — rather than generic primitives like Card or Container. That sounds cosmetic until your registry has forty components and two teams are independently proposing near-duplicate generic ones; semantic naming makes registry sprawl visible earlier.
Yelp's CHAOS: Consolidating Five Systems Into One
Yelp's account of building CHAOS ("Content Hosting Architecture with Optimization Strategies"), told across a series of Yelp Engineering Blog posts starting in March 2024, is less a success story about SDUI's benefits and more a cautionary one about SDUI sprawl — which is exactly why it belongs in this guide. Yelp's own telling: several product teams had already built independent, incompatible server-driven UI systems for their own features. Each was expensive to build and maintain, and none supported every one of Yelp's clients. CHAOS, begun in late 2021 and shipping its first production use case in early 2022, consolidated those into one framework serving both the consumer Yelp app and Yelp for Business across web, iOS and Android.
Architecturally, CHAOS runs on GraphQL rather than Lyft's protobuf approach: a client sends a GraphQL query, the CHAOS API constructs the response configuration server-side, and the client renders it. A later addition Yelp calls Konbini bridges CHAOS to Yelp's design system (Cookbook), generating matching component libraries in Python, Kotlin, Swift and TypeScript from a single JSON definition — a direct answer to the versioning-and-consistency problem that shows up whenever a design system and an SDUI registry are maintained by different teams on different schedules.
Google's Remote Compose and the Platform-Level Signal
Google's AndroidX Remote Compose library — currently version 1.0.0-alpha19, released September 9, 2026, with no stable release yet — is worth including here as a signal about where the underlying idea is heading at the platform level, even though it solves a narrower problem than Ghost Platform, Canvas or CHAOS. Remote Compose describes UI as a serialized document rendered by a separate "player" on a remote surface: a watch face, a home-screen widget, a car display, or another context that sits outside your app's normal in-process Compose tree. Google positioned it at Google I/O 2026 specifically around those remote-surface cases, including richer native rendering for Wear OS's widget surfaces (the rebranded successor to Wear Tiles).
That's a different job than an app restructuring its own main-screen content from a backend response. Remote Compose is about one app's UI reaching a surface outside that app's own process; Ghost Platform, Canvas and CHAOS are about a backend restructuring the screens inside an app that's already running. The two are complementary, not competing — a team could reasonably use Remote Compose for a widget while running a completely separate, in-house SDUI system for the main app's feed. Treat Remote Compose's existence as validation that Google sees enough demand for this general pattern to invest platform-level tooling in it, not as a drop-in replacement for the systems described above.
Open Source and Off-the-Shelf: DivKit and Applin
Not every team needs Airbnb's scale to justify the pattern, and not every team should build a renderer from scratch. Two open-source options sit at genuinely different points on the maturity spectrum.
| Option | Category | What You're Actually Getting | Maturity Signal | Maintainer |
|---|---|---|---|---|
| Build your own | In-house architecture | Full control of schema, versioning and registry; no third-party dependency risk | You own 100% of the maintenance cost — see Spotify's HubFramework retirement as the cautionary case | Not applicable — your own team |
| DivKit | Open-source SDUI framework (Apache 2.0) | A working, cross-platform (Android/iOS/web) renderer built and used internally by Yandex | Public GitHub history you can audit; thousands of commits, actively maintained as of this check | Maintained by Yandex; verify current activity before a long-term dependency |
| Applin | Open-source SDUI framework (Apache 2.0) | A minimal, backend-first SDUI toolkit aimed at small teams | Small, single-maintainer project — read the source before depending on it in production | Independently maintained (Leonhard LLC); verify maintenance activity directly |
DivKit is the more production-ready option: an Apache-2.0-licensed, cross-platform (Android, iOS, web) SDUI framework that Yandex built and uses internally across its own products, with a public commit history you can audit directly on GitHub before adopting it. Applin takes a more minimal, backend-first approach from an independent developer — a reasonable starting point to learn the pattern's mechanics on a small project, but not something we'd recommend without reading its source directly first, given its much smaller maintainer base.
Neither tool removes the obligations covered in the rest of this guide. Adopting DivKit or Applin changes who wrote your rendering layer; it doesn't change your responsibility to define a closed component registry, version your schema, build a fallback path, or validate every payload before acting on it.
When Server-Driven UI Is the Wrong Answer
Spotify's HubFramework is the cleanest public cautionary example available: an early, genuinely serious component-driven UI toolkit for iOS, supporting both local and backend-driven JSON layouts, archived by Spotify on GitHub on January 17, 2019 with a notice stating it was "being phased out at Spotify" and would not be maintained further. That's not evidence the pattern itself failed — Ghost Platform, Canvas and CHAOS are all considerably newer and differently architected, and none shows public signs of the same fate. It is evidence that an SDUI system is a multi-year maintenance commitment, not a one-time build, and that the org structure and tooling built around a given system can outlive its usefulness even when the underlying idea keeps proving itself elsewhere.
The engineering community's own accounting of the pattern's costs, gathered in a public discussion thread run by the MobileNativeFoundation — a working group of mobile engineers across multiple companies — lists the recurring drawbacks consistently: versioning problems when an old client hits a component it doesn't recognize, testing complexity because backend changes bypass the client-side gates a normal release would hit, payload bloat on complex screens, and a real organizational cost in keeping design, product and platform engineering aligned on one shared schema.
- Your screens are simple and stable: If most of your screens change rarely and a feature flag already covers your experimentation needs, a full SDUI system adds versioning and testing overhead you won't recoup.
- You don't have — or can't staff — a platform-owning team: Every production system in this guide has a named team responsible for the registry, schema and renderer. Treating SDUI as a side project for whichever engineer built the first screen is how Yelp ended up with five incompatible systems before CHAOS consolidated them.
- Your component vocabulary is still changing weekly: A registry that gets redesigned every sprint defeats the purpose — you'll spend more time versioning the registry than you save skipping app releases.
- You need to ship new business logic, not new layout: SDUI ships structure and data, not code. A genuine logic change — a new pricing rule, a new validation flow — still needs a client release or a carefully scoped, compliance-reviewed OTA code-push mechanism, covered next.
Security: Why a Server Response Is Still Untrusted Input
The instinct to trust an SDUI payload because "it's our own backend" is the actual vulnerability. OWASP's Mobile Top 10 2024 names this class of risk directly as M4, Insufficient Input/Output Validation — failing to properly validate data your app receives, whether from a user, a deep link, or an API response, before acting on it. A server-driven UI payload is exactly that kind of API response, and the relevant checklist for testing your renderer against it is OWASP's Mobile Application Security Verification Standard (MASVS), currently at version 2.1.0, which added a dedicated MASVS-PRIVACY category in January 2024 alongside its existing platform-interaction and data-validation controls.
The concrete failure mode isn't hypothetical: a compromised backend, a man-in-the-middle position on an unpinned connection, or simply a malformed response could — in a poorly designed schema — trigger a native action never anticipated at review time: opening an arbitrary deep link, firing a payment call, requesting a sensitive permission. This is the same untrusted-input discipline this site's deep linking guide applies to a deep link's query parameters, applied one layer up, to the action definitions inside an SDUI schema itself.
navigateTo, openWebView, trackEvent— each with its own validated argument shape, you've kept the blast radius of a bad or malicious payload bounded. If it's a generic function-call mechanism, you've rebuilt a remote code execution primitive and called it a UI framework.Apple Guideline 2.5.2: The Line SDUI Has to Respect
Apple's App Store Review Guideline 2.5.2 requires apps to be self-contained within their bundle and prohibits downloading, installing, or executing code that introduces or changes the app's features or functionality after review. Apple has not issued guidance naming "server-driven UI" specifically, but the boundary the guideline itself draws is unambiguous and is the one every system in this guide has operated inside for years: shipping structured data, rendered by native code that was already reviewed and shipped in the binary, is a different act from downloading and running new code.
Apple made that boundary very publicly concrete in the spring of 2026. Vibe-coding apps — tools that let non-programmers generate and run working software directly on their phones using an AI model — drove an 84% surge in App Store submissions in the first quarter of 2026, and Apple escalated enforcement of Guideline 2.5.2 against them starting in March: blocking updates to Replit and Vibecode, then removing a third app, Anything, from the store entirely on March 26 — twice, after it briefly returned. The violation in each case was the same one this guide has been describing throughout: those apps let users generate and execute genuinely new logic on-device after Apple had already reviewed the shell app around it.
The same 2.5.2 boundary is also why CodePush-style over-the-air JavaScript patching has always carried more App Store policy risk than SDUI, whatever its other engineering merits — it ships and executes new logic by design. Microsoft retired Visual Studio App Center, including its hosted CodePush service, on March 31, 2025, and archived the CodePush server repository on GitHub that May; teams still depending on it have migrated to Microsoft's standalone, self-hosted CodePush server or to their own OTA infrastructure, carrying the same underlying compliance exposure either way. If your broader mobile security and compliance posture hasn't had a structured review recently, our mobile app security guide covers the wider surface this section is one slice of.
Reference Architecture and the Order to Build It In
The build order matters for the same reason it does in this site's deep linking and push notification guides: each step either depends on the one before it, or fails silently without it.
| Step | What | Failure Mode If Skipped | Why This Order |
|---|---|---|---|
| 1 | Define the component and action registries — the fixed, closed vocabulary of native components (and the actions they can trigger) the server is ever allowed to reference. | Every later mitigation depends on this vocabulary being closed, not open-ended | Get this list reviewed by whoever owns your Apple/Google compliance posture before writing a renderer — it's the artifact that proves you ship data, not code. |
| 2 | Design the schema — the JSON/protobuf/GraphQL shape the server uses to describe a screen, including a version field on every payload. | Silent breakage when the schema changes with no way for the client to know which version it's looking at | Depends on step 1's vocabulary being stable enough to encode. |
| 3 | Build the client-side renderer with a mandatory fallback path for any component type or version it doesn't recognize. | The most-cited real-world SDUI crash: an old app version hits a component it has no code for | Must exist before any production rollout, not added after the first incident. |
| 4 | Validate every incoming payload server-side and client-side before rendering or dispatching any action from it — never trust an action definition as pre-authorized. | A malformed or compromised payload triggers a native action (a deep link, a payment call, a permission prompt) the app's reviewed behavior never anticipated | This is the OWASP M4 / MASVS control point discussed in the security section — implement it before scaling usage, not after. |
| 5 | Wire in versioned rollout via your existing experimentation/feature-flag infrastructure, not a separate ad hoc mechanism. | No staged rollout means a bad payload reaches 100% of clients before anyone notices | Depends on 1–4 being stable; this is how Airbnb, Lyft and Yelp all layer SDUI on top of tooling they already had, not instead of it. |
| 6 | Build backend contract tests and client-side snapshot tests against a matrix of known payload shapes. | Backend changes ship with none of the testing a client release would have forced | Last, because it tests the pipeline steps 1–5 already established. |
One ownership note that Yelp's pre-CHAOS history illustrates directly: the registry and schema need one named owner across every team that touches them, not a convention each team is trusted to follow independently. The moment a second team starts extending the registry without the first team's sign-off, you're re-accumulating the sprawl CHAOS was built to undo — and this time with a production security surface, not just a maintenance headache.
If you're still deciding between a cross-platform framework and fully native development before any of this becomes relevant, our React Native vs. Flutter comparison and cloud architecture guide cover the backend and client foundations an SDUI layer sits on top of, and our API development guide covers the schema-design and versioning discipline this architecture leans on most heavily.
What Server-Driven UI Actually Saves: A Worked Scenario
The following is an illustrative worked scenario, not a real client engagement or a reported outcome — the arithmetic uses realistic, stated assumptions to make the tradeoff concrete, deliberately without borrowing the unverified Lyft figure discussed above.
Consider a 25-person product team at a subscription app running roughly one homepage layout experiment per month on each platform — reordering sections, testing a new card type, adjusting which promotion surfaces first. Under a fully client-driven architecture, each variant requires a client code change, a full QA cycle, and submission to both app stores; assume a conservative, stated 3-to-5-business-day round trip once a build is submitted (Apple and Google both publish review-time guidance in that general range for a routine update, with no fixed SLA on either platform), on top of whatever internal QA time the change already needed.
| Approach | Where the layout logic lives | What still requires a release | What no longer does |
|---|---|---|---|
| Fully client-driven | Hardcoded in each platform's binary | Every experiment variant, on both platforms, every time | Nothing — this is the baseline |
| Server-driven UI, closed registry | A backend schema, rendered by a pre-shipped native registry | A genuinely new component type entering the registry for the first time | Reordering, swapping, or A/B-testing arrangements of components already in the registry |
The honest reading of that table is not "SDUI eliminates app store review" — it doesn't, and the compliance section above explains exactly where the remaining boundary sits. The honest reading is narrower and still valuable: for the specific, recurring class of change this team runs monthly (reordering and swapping components already in a stable registry), the review-cycle dependency moves from "every single time" to "only when the registry itself needs to grow" — which, for a team with a reasonably stable component vocabulary, is a meaningfully smaller and rarer event than a monthly experiment cadence. The team still needs the backend contract testing and fallback rendering covered earlier in this guide; SDUI moves where the release bottleneck sits, it doesn't remove the engineering discipline the bottleneck was partly enforcing.
Red Flags in Vendor and Agency Proposals
| Claim | Reality |
|---|---|
| "Server-driven UI lets you skip App Store review completely" | SDUI reduces how often you need a review cycle for a specific class of screen-structure change; it does not exempt an app from review, and a proposal that frames it as review-avoidance misunderstands Guideline 2.5.2's actual boundary — see the compliance section. |
| A component/action schema with no closed registry — "the server can call any native function" | That's the anti-pattern this guide's security section names directly. A schema expressive enough to invoke arbitrary native functionality is a standing OWASP M4 input-validation risk, not a feature. |
| No mention of a fallback path for components an older app version doesn't recognize | This is the most commonly reported production SDUI crash. A team proposing SDUI with no stated versioning or fallback strategy hasn't shipped this pattern into a real, multi-version install base before. |
| A quoted experiment-velocity or 'ships X times faster' number with no named source | The 'two weeks to two days' figure attributed to Lyft circulates without independent confirmation against Lyft's own post — see the FAQ. A vendor repeating it as settled fact is repeating an unverified secondary claim, not reporting a measured result. |
| No plan for backend contract testing or client-side snapshot testing against payload shapes | Backend changes to an SDUI payload bypass the client-side and App Store review testing gates a normal release would hit; a proposal silent on this has moved your testing burden onto production incidents instead of removing it. |
If you're evaluating a broader app rebuild proposal that includes SDUI as one line item among several, our mobile app RFP template guide covers how to write scope language specific enough that competing agencies' "server-driven" claims are actually comparable to each other, rather than each vendor claiming the same word at very different levels of rigor.
What This Costs, and Its Limits
| Engagement | Range | Timeline | Typical Scope |
|---|---|---|---|
| Discovery + component/schema audit | $9k–$22k | 2–4 weeks | Screen inventory, component/action registry draft, versus-feature-flag scoping |
| Single-platform proof of concept | $28k–$70k | 4–9 weeks | One native client, closed schema, fallback renderer, feature-flagged cohort rollout |
| Cross-platform SDUI system | $70k–$180k | 9–16 weeks | iOS + Android + web, shared schema, versioning strategy, design-system bridge |
| Enterprise / regulated build | $180k–$420k+ | 14–24 weeks | Audit logging, documented MASVS-aligned security review, dedicated platform support process |
One scoping note specific to this architecture: the discovery phase should always start with a screen-by-screen audit of what genuinely needs server-side structural control versus what a feature flag or a simpler content API already handles — the single most common overspend we see in this category is a team building a full SDUI registry and renderer for two or three screens that a remote-config toggle would have covered at a fraction of the cost and none of the versioning overhead.
None of this replaces your own legal and security review against your specific schema, registry and App Store category — a guide like this one can only describe the current state of several companies' public engineering accounts and one platform vendor's published rules as of the date it was checked, not guarantee neither has shifted by the time you read it.
Get Your Screen Inventory Scoped for Server-Driven UI
Book a free 60-minute discovery call with Frenchy Digital, a senior-led Black-owned Los Angeles agency. We review which of your screens actually need server control versus a simpler feature flag, and send a written, fixed-price phased proposal within 5 business days.
1517 S Bentley Ave Unit 204, Los Angeles CA 90025
Frequently Asked Questions
Sources & References
- 1Android Developers — Remote Compose (Jetpack/AndroidX release notes)↗
- 2Android Developers Blog — 17 Things to Know for Android Developers at Google I/O 2026↗
- 3GitHub — divkit/divkit (open-source Server-Driven UI framework)↗
- 4GitHub — spotify/HubFramework (archived)↗
- 5Airbnb Tech Blog (Medium) — A Deep Dive into Airbnb's Server-Driven UI System, by Ryan Brooks↗
- 6Lyft Engineering — The Journey to Server Driven UI at Lyft Bikes and Scooters, by Alex Hartwell↗
- 7Yelp Engineering Blog — CHAOS: Yelp's Unified Framework for Server-Driven UI (March 2024)↗
- 8Yelp Engineering Blog — Exploring CHAOS: Building a Backend for Server-Driven UI (July 2025)↗
- 9Yelp Engineering Blog — How Yelp Keeps Server-Driven UI Consistent Across Four Platforms (April 2026)↗
- 10GitHub — MobileNativeFoundation Discussions #47: Server-driven UI (or Backend driven UI) strategies↗
- 11Applin — Server-Driven UI Framework for Mobile Apps↗
- 12Apple Developer — App Review Guidelines (Section 2.5.2 and 2.3.1)↗
- 13TechCrunch — How Vibe-Coding App Anything Is Rebuilding After Getting Booted From the App Store Twice↗
- 14MacRumors — Apple Pulls Vibe Coding App 'Anything' From App Store, Escalating Enforcement↗
- 15Microsoft Learn — Visual Studio App Center Retirement↗
- 16GitHub — microsoft/code-push-server (standalone CodePush server)↗
- 17OWASP — Mobile Top 10 2024, M4: Insufficient Input/Output Validation↗
- 18OWASP Mobile Application Security — MASVS (Mobile Application Security Verification Standard)↗
- 19OWASP MAS — MASVS v2.1.0 Release & MASVS-PRIVACY announcement↗

