8 min read · Updated May 2025

Server-Driven UI in React Native - The Complete Guide

Server driven UI React Native architecture removes the wall between product changes and App Store review. Instead of hardcoding every screen, your app renders a schema fetched from the server.

Netflix, Airbnb, and Shopify use this pattern at scale. Applied to onboarding, it lets PMs change copy, fields, ordering, and requirements without a release.

What is Server-Driven UI?

In a traditional React Native app, your UI is defined in code: which components render, in what order, with what content. Change anything and you need a new build.

In a server-driven app, your server sends a description of what to render. The app reads that description and renders the appropriate components.

Traditional:
  Code defines UI -> build -> ship -> App Store -> 2 weeks

Server-Driven:
  Server defines UI -> app fetches -> renders -> instant

Why React Native teams use SDUI

  • Skip App Store review for UI changes. Any UI change driven by the server does not require a new binary.
  • PM self-serve. A PM with a dashboard can update copy, reorder fields, or add a screen in minutes.
  • A/B testing at scale. Serve different UI descriptions to different user segments without code changes.
  • Instant rollback. Ship a bad UI change, roll back on the server, and users get the previous version on next app open.

The core architecture

The simplest SDUI implementation has three parts: a schema, a renderer, and a fetch/cache layer.

{
  "screens": [
    {
      "id": "screen_profile",
      "components": [
        {
          "type": "heading",
          "content": { "text": "Tell us about you" }
        },
        {
          "type": "textInput",
          "field": { "id": "inp_name", "required": true },
          "content": { "label": "Full name", "placeholder": "Jane Smith" }
        }
      ]
    }
  ]
}
const COMPONENT_MAP = {
  heading: HeadingComponent,
  textInput: TextInputComponent,
  toggle: ToggleComponent,
}

function SDUIRenderer({ schema }) {
  return (
    <View>
      {schema.components.map((component) => {
        const Component = COMPONENT_MAP[component.type]
        return Component ? (
          <Component key={component.id} config={component} />
        ) : null
      })}
    </View>
  )
}
function useSDUISchema(endpoint: string) {
  const [schema, setSchema] = useState(null)

  useEffect(() => {
    AsyncStorage.getItem('schema').then((cached) => {
      if (cached) setSchema(JSON.parse(cached))
    })

    fetch(endpoint)
      .then((r) => r.json())
      .then((data) => {
        setSchema(data)
        AsyncStorage.setItem('schema', JSON.stringify(data))
      })
  }, [endpoint])

  return schema
}

The component registry pattern

The key architectural decision in SDUI is your component registry: the map between schema type strings and React Native components.

const registry = {
  textInput: MyTextInput,
  dateSelect: MyDatePicker,
  roleCards: MyOptionCards,
}

function Renderer({ component, registry }) {
  const Component = registry[component.type]
  if (!Component) return null
  return <Component config={component} />
}

New component type added to your schema? Add it to the registry. Nothing else changes. This is what makes SDUI scalable.

The navigation layer

Basic SDUI handles rendering. The harder problem is navigation: how do you enforce that users complete certain screens before accessing the app?

function useSDUIGuard(schema, userProgress) {
  const nextRequired = schema.screens.find((screen) => {
    const isRequired = screen.mandatory
    const isComplete = userProgress[screen.id] === 'complete'
    return isRequired && !isComplete
  })

  return {
    shouldBlock: !!nextRequired,
    resumeScreen: nextRequired?.id ?? null,
  }
}

Versioning your schema

{ "version": 7, "screens": [] }
const fresh = await fetchSchema()
const cached = await getCache()

if (!cached || fresh.version > cached.version) {
  await setCache(fresh)
  setSchema(fresh)
} else {
  setSchema(cached)
}

Never update the schema mid-flow. Buffer new versions and apply them on the next session start.

Summary

Server-Driven UI is proven at scale. Applied to React Native onboarding, it removes the App Store release cycle from onboarding changes, gives PMs self-serve control, and unlocks field-level analytics.

The three pieces are a JSON schema, a component registry, and a navigation guard. Build all three yourself or use Recus to get them in one install.