How to Ship Mobile UI Changes Without App Store Review

A practical guide to implementing server-driven UI in your native iOS and Android apps. Update your UI in seconds, not days.

You want to change your app's UI without waiting for app store review. Maybe it's a button label, an onboarding flow, or an A/B test. This guide shows you how to make that happen.

We'll cover the architecture, implementation approaches, and practical steps to get started.

The Core Concept

Traditional mobile apps have UI hardcoded in the binary. Every layout, every button, every piece of text is compiled into your app. To change it, you need a new build.

Server-driven UI flips this. The UI is defined on your server and rendered dynamically on the client. Your app knows how to render components, but which components appear (and what data they show) comes from your backend.

// Server response defines the UI { "screen": "welcome", "components": [ { "type": "title", "text": "Welcome to Acme" }, { "type": "image", "src": "hero.png" }, { "type": "button", "text": "Get Started", "action": "navigate:home" } ] }

The app receives this JSON and renders native SwiftUI or Jetpack Compose views. Change the JSON on your server, and the app shows the new UI — no app store review needed.

Three Approaches

There are three ways to implement this:

Build Custom

Build your own SDUI infrastructure from scratch.

✓ Full control
✗ 6-12 months to build

Open Source

Use DivKit (Yandex), Stac (Flutter), or similar.

✓ Free, no vendor lock-in
✗ Limited tooling, DIY

Platform

Use Pyramid, Judo, or Nativeblocks.

✓ Ready to use, visual editor
✗ Vendor dependency, cost

Implementation Steps (Custom or Open Source)

If you're building custom or using open source, here are the key steps:

1 Define Your Component System

Create a mapping between server component types and native views. Start simple:

  • text → SwiftUI Text / Compose Text
  • imageAsyncImage / AsyncImage
  • buttonButton / Button
  • stackVStack/HStack / Column/Row

Don't try to support everything. Start with the components you actually need for your first server-driven screen.

2 Build Your Rendering Engine

Create a function that takes a server response and returns native views:

// Pseudocode func render(component: ServerComponent) -> View { switch component.type { case "text": return Text(component.text) case "image": return AsyncImage(url: component.src) case "button": return Button(component.text) { handle(component.action) } case "stack": return VStack { component.children.map(render) } } }

3 Handle Actions

Components need to do things — navigate, call APIs, show dialogs. Define an action system:

  • navigate:screenId → Push a new screen
  • openUrl:https://... → Open external URL
  • api:endpoint → Make an API call
  • dismiss → Close current screen

4 Add Your Custom Components

You'll want to use your existing design system. Register custom components that the server can reference:

// Register your design system components componentRegistry.register("ProductCard", ProductCardView.self) componentRegistry.register("UserAvatar", UserAvatarView.self) componentRegistry.register("PriceTag", PriceTagView.self)

Now your server can send {"type": "ProductCard", "productId": "123"} and your app renders it.

5 Build Your Backend

Create an API endpoint that returns screen definitions. This can be:

  • Static JSON — Files stored in S3/CDN, fast to update
  • Dynamic API — Generated per-request, enables personalization
  • GraphQL — What Airbnb uses, strongly typed

Start simple. Static JSON behind a CDN works for most use cases.

6 Add Caching

You don't want to fetch UI definitions on every screen load. Implement caching:

  • In-memory cache — For current session
  • Disk cache — For offline support
  • Prefetching — Load next screens before user navigates

What NOT to Do

⚠️ Don't Use Hot Updates for New Features

CodePush (React Native) and similar tools let you push JavaScript updates without app store review. But Apple's guidelines restrict this to "bug fixes" — using it for new features risks app rejection.

Server-driven UI is architecturally different. You're not pushing code; you're fetching data that happens to describe UI. This is compliant with app store guidelines.

Start Small

Don't try to make your entire app server-driven overnight. Start with:

Once you've proven the pattern works, expand to more critical screens.

Or Skip the Build Phase

Building SDUI infrastructure takes time — typically 3-6 months for a basic system, longer for something production-ready with visual tooling.

If you want the benefits without the build time, that's why we made Pyramid.

Skip the Infrastructure Work

Get server-driven UI in your app this week, not next quarter.

Get Early Access →