Skip to content
OTFotf
All posts

Expo SDK 56 killed the platform-specific file — one component renders on iOS, Android, and web

D
DaveAuthor
7 min read
Expo SDK 56 killed the platform-specific file — one component renders on iOS, Android, and web

For years, the price of "write once, run on iOS, Android, and web" was a folder full of forks: Button.tsx, Button.ios.tsx, Button.web.tsx, sometimes Button.native.tsx. The bundler picked the right one per platform. It worked, but it meant the thing you called <Button> was three or four different files kept in sync by hand. Change the API in one, forget the others, and you ship a bug that only happens on Android.

Expo SDK 56, released May 21 2026 on React Native 0.85 and React 19.2, retires that pattern as the default. Its universal components render on all three platforms from a single definition — no .ios.tsx, no .web.tsx. One file, three targets. The SDK 56 changelog marks the moment plainly: Expo UI is now ready for production. This is a bigger deal than a release note suggests. It moves "one component, every platform" from a thing you bolt on with a build trick to a thing the platform hands you. And it validates a bet some of us made a while ago.

What SDK 56 actually ships

The citable facts first. SDK 56 is pinned to React Native 0.85 and React 19.2, with Hermes as the default engine — all per the official changelog. On top of that runtime sits the universal component surface: layout and text primitives that resolve to real native views on mobile and to flexbox equivalents on web. You write the structure once; the platform resolves the primitive.

The shape of the API at launch looked like this — a single import, no platform suffixes:

// Single definition. Renders on iOS, Android, and web.
import { Host, Column, Row, Text } from 'expo/ui'

export function StatRow() {
  return (
    <Host>
      <Column>
        <Text>Revenue</Text>
        <Row>
          <Text>$4,200</Text>
          <Text>+12%</Text>
        </Row>
      </Column>
    </Host>
  )
}

Two honest hedges belong here, because this surface is young and version-sensitive. First, treat the exact export names above as the launch shape of the API, not scripture — confirm them against the current Expo UI reference (linked from the SDK 56 changelog) before you build on them, since beta-era names can be renamed or reshaped. Note that the Expo UI docs have moved around since launch, so do not rely on a guessed docs URL; start from the changelog and follow its links. Second, the launch-period coverage cited patch-level versions (React Native 0.85.x, React 19.2.x) that have since moved — pin your own versions from expo-doctor, not from a blog post. The durable claim, the one the changelog itself supports, is simpler: as of SDK 56, universal UI is production-ready and it is the platform's official direction.

Host is the bridge to the native view tree. Row and Column are layout primitives mapping to real native layout on mobile and flexbox on web. Text is a text node on native and a span-equivalent on web. The takeaway stands regardless of naming details: the platform-specific file is no longer the default unit of cross-platform UI. The component is.

Why the file-split was a tax, not a feature

The .ios.tsx / .web.tsx convention was always a workaround for one underlying problem: web and native have different primitives (<div> versus UIView), so the same component needed two implementations. The convention let you colocate those implementations under one import name. Useful — but it pushed the cost onto you:

  • Drift. Two files, one API. The moment you edit one, the other is stale until you remember it exists.
  • Doubled surface. Every prop, every variant, every edge case, written twice.
  • Illegibility for AI. A coding agent that opens Button.tsx sees half the truth. The web behaviour lives in Button.web.tsx, which it may not even read. It generates a call that works on one platform and silently breaks on the other.

That last one matters more every month. If your codebase is going to be read and extended by Claude Code or Cursor, a single-file component is not just cleaner — it is the difference between the agent getting it right and the agent guessing. Universal components collapse the two-file tax into one. That is the win SDK 56 ships.

One codebase. iOS, Android, and web.

The Fitness Kit ships with auth, a database, and a backend already connected — no setup. Live demo at fitness-preview.otf-kit.dev.

See the live demo

The same-API thesis, validated from the platform side

Here is why this release is worth a whole post instead of a footnote: the universal-component model is the exact bet behind cross-platform component libraries that expose one name, one set of props, with the platform difference resolved underneath. That is the architecture we describe in one component across web and mobile and the single-codebase strategy: the platform difference belongs inside the library, resolved once and tested — not scattered across your app as .ios and .web forks.

The thesis was always that a shared design-token layer plus same-API components lets "add a screen" extend the grid instead of improvising per platform — the argument our design-system-as-agent-context guide makes from the agent's point of view. SDK 56 makes that the platform's official position too. When the framework itself ships universal primitives as production-ready, "same component, every platform" stops being an opinion and becomes the grain you work with.

Primitives are the floor, not the ceiling

A fair pushback: layout and text primitives are the floor. Real apps need a data table, a command palette, a sheet, a date picker, charts. SDK 56 gives you the universal foundation; it does not give you the hundred-plus-component surface a product actually ships with.

That is the gap a component library fills on top of the universal primitives: the opinionated, accessible, themed components — same API on web and native — built on the floor the framework now provides. SDK 56 makes the foundation universal; a library makes the whole UI universal, and ships the agent-config layer (CLAUDE.md, tested prompts) so an agent extends it without inventing conventions. Expo Router, the open-source universal routing library, completes the picture on the navigation side — one routing surface alongside one component surface.

Before you adopt: verify two things

Because this API is young, a retrofit-grade adoption checklist is short but non-negotiable. One, open the current Expo UI reference from the SDK 56 changelog links and confirm every export name you import — if Host, Row, or Column were renamed after the beta window, your code should use the new names, and any tutorial (this one included) showing the old ones is stale. Two, run the upgrade on a branch with expo-doctor green and your Reanimated-heavy screens tested on a real device, keeping in mind the Hermes V1 memory regression Expo documented after SDK 56 shipped and fixed in SDK 57. Neither step takes long, and both are cheaper than debugging a renamed export in CI.

What this enables

When the component is the unit and the file-split is gone:

  • One mental model. Learn the layout primitives once; they behave the same on the phone and in the browser.
  • One thing to fix. A layout bug is fixed in one place, not "in one place and also the .web variant."
  • Agent-legible by default. A single-file universal component is fully visible to a coding agent in one read — no hunting for a platform variant it might miss.
  • A real expo run:ios, expo run:android, and web build from one source — which was the promise the file-split convention only ever half-delivered.

The platform-specific file had a good run. SDK 56 is the signal that the era of forking components per platform is ending — and that building on a same-API component layer, rather than around it, is now the path with the grain instead of against it. Start new screens on the universal surface today, migrate old screens when you touch them, and build on OTF kits if you want that component layer, the tokens, and the agent conventions shipped as one starting point your coding agent can extend to production.

Sources

  • Expo SDK 56 changelog — release date (May 21 2026), React Native 0.85, React 19.2, Expo UI production-ready, Hermes V1 regression note fixed in SDK 57.
  • Expo Router introduction — Expo Router as the open-source universal routing library for Expo apps.
  • OTF kits — full-stack kits with cross-platform component systems agents can anchor to.
react-nativecross-platformdesign-system
OTF Fitness Kit

Stop wiring. Start shipping.

  • Login, database, and backend already connected — nothing to set up
  • iOS + Android + web from one codebase
  • AI configs pre-tuned + 40+ tested prompts included
Need more than components?

Full-stack kits.
Pay once, own the code.

SaaS Dashboard and Fitness include authentication and a database. Arcade is browse-first with a local demo session and no backend sign-in by default. Booking is in Preview; Marketplace is coming soon and not currently sold. The Bundle includes the three live kits.

Everything Bundle — $149See full pricing

Get the free AI configs pack

Pre-tuned AI configs for Cursor, Claude, and Lovable — drop them in and your AI tool instantly understands your project.

No spam. Unsubscribe any time.

Prefer the free SDK? Star it on GitHub →