●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Rork Max × Server-Driven UI— Control Your App's UI in Real Time from the Backend
Learn how to implement Server-Driven UI (SDUI) in Rork Max. Deliver UI components as JSON from your backend and dynamically update app layouts without app store reviews.
What Is Server-Driven UI — and Why It Matters for Mobile Development
In traditional mobile development, every UI change requires a new app store submission and review cycle. This creates a frustrating gap between what your business needs and what you can actually ship. Server-Driven UI (SDUI) solves this problem at its root.
The core idea is elegantly simple: define your UI layout, structure, and display conditions as a JSON response from the server, and let the client (your app) interpret that JSON to render the appropriate components. Companies like Airbnb, Shopify, and Lyft use this pattern in production to power instant A/B test switching and personalized UI delivery.
Rork Max generates native apps built on React Native and Expo, making it an excellent fit for the SDUI pattern. In this guide, we'll walk through the design principles, JSON schema, rendering engine, and backend architecture you need to bring SDUI into your Rork Max project.
SDUI Design Principles — The Three Core Layers
An SDUI architecture consists of three distinct layers.
Layer 1: Schema Definition (Contract Layer)
This is the "contract" between your server and client — the JSON schema that defines what components exist and how they're configured. This schema is the backbone of SDUI and deserves careful thought.
The backend serves JSON definitions while the client handles caching for optimal performance.
// hooks/useSDUIScreen.ts — Screen data fetching with cache managementimport { useState, useEffect, useCallback } from 'react';import AsyncStorage from '@react-native-async-storage/async-storage';const SDUI_CACHE_PREFIX = 'sdui_cache_';export function useSDUIScreen(screenId: string) { const [screen, setScreen] = useState<SDUIScreenResponse | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null); const fetchScreen = useCallback(async () => { try { // 1. Check cache first (offline support) const cached = await AsyncStorage.getItem( `${SDUI_CACHE_PREFIX}${screenId}` ); if (cached) { const parsed = JSON.parse(cached); const isExpired = Date.now() - parsed.cachedAt > parsed.data.ttl * 1000; if (!isExpired) { setScreen(parsed.data); setLoading(false); return; } } // 2. Fetch latest data from server const response = await fetch( `https://api.example.com/sdui/screens/${screenId}`, { headers: { 'X-App-Version': '2.1.0', 'X-Platform': Platform.OS, }, } ); const data: SDUIScreenResponse = await response.json(); // 3. Save to cache await AsyncStorage.setItem( `${SDUI_CACHE_PREFIX}${screenId}`, JSON.stringify({ data, cachedAt: Date.now() }) ); setScreen(data); } catch (err) { setError(err as Error); // Fallback: show stale cache rather than nothing const cached = await AsyncStorage.getItem( `${SDUI_CACHE_PREFIX}${screenId}` ); if (cached) { setScreen(JSON.parse(cached).data); } } finally { setLoading(false); } }, [screenId]); useEffect(() => { fetchScreen(); }, [fetchScreen]); return { screen, loading, error, refetch: fetchScreen };}
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Understand SDUI design principles and JSON schema definitions from concept to production-ready implementation
✦Build a release workflow that updates your app's UI instantly without app store review
✦Apply the same SDUI patterns used by Airbnb and Shopify to your Rork Max projects
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Implementation Tutorial — Adding SDUI to Your Rork Max Project
Step 1: Build a Backend API with Supabase
SDUI requires a backend that manages screen definitions and serves them via API. Building on the Supabase integration patterns for Rork, we'll add SDUI-specific tables.
-- Run in Supabase SQL Editor-- Screen definitions tableCREATE TABLE sdui_screens ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), screen_id TEXT UNIQUE NOT NULL, -- e.g., 'home', 'product_detail' version INTEGER NOT NULL DEFAULT 1, components JSONB NOT NULL, -- Array of SDUIComponent metadata JSONB DEFAULT '{}', ttl INTEGER DEFAULT 300, -- Cache TTL in seconds is_active BOOLEAN DEFAULT true, targeting JSONB DEFAULT '{}', -- A/B test and segment conditions created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW());-- Version history table (for rollbacks)CREATE TABLE sdui_screen_versions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), screen_id TEXT REFERENCES sdui_screens(screen_id), version INTEGER NOT NULL, components JSONB NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW());-- RLS policies: public read, admin-only writeALTER TABLE sdui_screens ENABLE ROW LEVEL SECURITY;CREATE POLICY "Public read" ON sdui_screens FOR SELECT USING (is_active = true);
Step 2: Create a Delivery API with Supabase Edge Functions
Update this JSON in your database, and your app's UI changes immediately. No app store review required.
A/B Testing and Personalization — Where SDUI Truly Shines
One of SDUI's most compelling advantages is server-side A/B test control.
// utils/abTest.ts — A/B test resolution logicinterface ABTestConfig { testId: string; variants: { id: string; weight: number; // Distribution ratio from 0–100 components: SDUIComponent[]; }[];}export function resolveABTest( config: ABTestConfig, userId: string): SDUIComponent[] { // Deterministic hash based on user ID (same user always sees same variant) const hash = simpleHash(`${config.testId}:${userId}`); const bucket = hash % 100; let cumulative = 0; for (const variant of config.variants) { cumulative += variant.weight; if (bucket < cumulative) { return variant.components; } } // Fallback: first variant return config.variants[0].components;}function simpleHash(str: string): number { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash |= 0; } return Math.abs(hash);}// Usage: A/B test CTA button color and text// Variant A (50%): Blue button "Get Started"// Variant B (50%): Green button "Try Free"
Personalization works the same way — return different component arrays based on user attributes like plan tier, usage frequency, or region. This lets you show premium members a dedicated UI while displaying upgrade CTAs to free users, all without touching code.
Performance Optimization — Production Considerations
When running SDUI in production, performance is your top priority. Building on the Rork Max performance optimization guide, here are SDUI-specific optimizations.
Prefetching and Cache Strategy
// utils/sduiPrefetch.ts — Prefetch screens before navigationimport { SDUIScreenResponse } from '../types/sdui';const prefetchCache = new Map<string, Promise<SDUIScreenResponse>>();export function prefetchScreen(screenId: string): void { if (prefetchCache.has(screenId)) return; const promise = fetch( `https://api.example.com/sdui/screens/${screenId}` ).then((res) => res.json()); prefetchCache.set(screenId, promise); // Clear cache after 5 minutes setTimeout(() => prefetchCache.delete(screenId), 5 * 60 * 1000);}export async function getPrefetchedScreen( screenId: string): Promise<SDUIScreenResponse | null> { const cached = prefetchCache.get(screenId); if (cached) { prefetchCache.delete(screenId); return cached; } return null;}// Usage: When showing the home screen, prefetch screens the user is likely to visit// prefetchScreen('product_detail');// prefetchScreen('category_list');
Lazy-Loading Components
// components/sdui/LazyRegistry.ts — Load only the components you needimport { lazy, ComponentType } from 'react';const LAZY_REGISTRY: Record<string, () => Promise<{ default: ComponentType<any> }>> = { hero_banner: () => import('./HeroBanner'), product_grid: () => import('./ProductGrid'), text_block: () => import('./TextBlock'), cta_button: () => import('./CTAButton'), carousel: () => import('./Carousel'), feature_list: () => import('./FeatureList'), testimonial: () => import('./Testimonial'), video_player: () => import('./VideoPlayer'), // Heavy component};export function getLazyComponent(type: string): ComponentType<any> | null { const loader = LAZY_REGISTRY[type]; if (!loader) return null; return lazy(loader);}// Expected effect: Reduced initial bundle size — only used components are loaded
Error Handling and Fallback Strategies
In production, you need robust handling for server outages and malformed JSON responses.
// components/sdui/SafeSDUIRenderer.tsx — Renderer with error boundaryimport React, { Component, ErrorInfo, ReactNode } from 'react';import { View, Text, StyleSheet } from 'react-native';interface ErrorBoundaryState { hasError: boolean; errorComponent: string | null;}class SDUIErrorBoundary extends Component< { componentId: string; children: ReactNode }, ErrorBoundaryState> { state: ErrorBoundaryState = { hasError: false, errorComponent: null }; static getDerivedStateFromError(): ErrorBoundaryState { return { hasError: true, errorComponent: null }; } componentDidCatch(error: Error, info: ErrorInfo) { // Send error to analytics service console.error( `SDUI component error [${this.props.componentId}]:`, error, info ); } render() { if (this.state.hasError) { // Skip only the broken component — don't crash the whole screen return null; } return this.props.children; }}// Hardcoded fallback screen definitionsconst FALLBACK_SCREENS: Record<string, SDUIComponent[]> = { home: [ { id: 'fallback-welcome', type: 'text_block', props: { text: 'Thank you for using our app', variant: 'heading', }, }, ],};// When server fetch fails, display hardcoded fallbackexport function getFallbackScreen(screenId: string): SDUIComponent[] { return FALLBACK_SCREENS[screenId] || [];}
Testing Strategy — Ensuring SDUI Quality
With SDUI, JSON schema validation testing becomes critical. On top of Rork Max's testing strategies, add SDUI-specific tests.
Server-Driven UI is a powerful architectural pattern that solves the fundamental "slow release cycle" problem in mobile development. Combined with Rork Max's React Native and Expo foundation, SDUI lets you update your app's UI in real time without waiting for app store reviews, while enabling instant A/B testing and personalization.
The JSON schema design, rendering engine, caching strategy, and error handling patterns covered in this guide are ready for production use. Start by converting a single section of your home screen to SDUI and see the results for yourself.
To dive deeper into the concepts behind this guide,
Share
Thank You for Reading
Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.