EmpireUI
Get Pro
← Blog8 min read#react-native#expo#cross-platform

React Native vs Expo: Which to Use for Cross-Platform in 2026

React Native vs Expo in 2026 — what's actually different, when bare workflow beats managed, and which one ships faster for real apps.

A developer working on a mobile app using React Native and Expo on a MacBook with an Android phone beside it

The Real Difference Between React Native and Expo

Honestly, most comparisons of React Native vs Expo get this wrong from the start — they treat them like two competing frameworks when Expo is actually built on top of React Native. That distinction matters a lot once you're six months into a project.

React Native is the core framework from Meta. It gives you JavaScript (or TypeScript) that bridges into native iOS and Android code. You write components, it renders native views. No browser DOM involved. The catch is that you manage your own build pipeline, native modules, Xcode projects, and Gradle configs.

Expo is a set of tools, libraries, and services that sit on top of React Native. The Expo SDK (currently at 52.0 as of late 2026) pre-bundles a huge library of native modules — camera, notifications, location, file system — so you don't have to wire them up yourself. It also ships its own build service (EAS Build), update service (EAS Update), and a development client that runs your app in a shared sandbox.

So the question isn't really React Native vs Expo. It's: do you want to manage native layers yourself, or do you want Expo to abstract them? Neither answer is universally correct.

Expo Managed vs Bare Workflow: Know the Tradeoff

Expo ships in two modes. Managed workflow means Expo controls your native projects — you never open Xcode or Android Studio. Bare workflow means Expo generated the native folders for you, and now you own them. This is closer to plain React Native with Expo's SDK still available.

Managed workflow is fast. You run npx create-expo-app my-app, write your screens, and you're deploying to physical devices in under an hour. The development experience with Expo Go is genuinely good — scan a QR code, app loads instantly, hot reload works. For prototyping and MVPs, nothing comes close.

But managed workflow has a hard ceiling. If you need a native module that isn't in the Expo SDK — say, a custom Bluetooth LE library, a proprietary SDK from a payment terminal vendor, or some deeply specific platform API — you're stuck. You either eject to bare workflow (which is a real migration, not a toggle) or you build a custom Expo config plugin, which requires understanding native code anyway.

Bare workflow gives you everything. Full access to android/ and ios/ directories, any CocoaPod, any Gradle dependency. You can still use expo-modules-core and most of the Expo SDK. But now you're responsible for keeping native deps in sync. That's a meaningful maintenance burden, especially across iOS SDK updates.

Setting Up a Project: Commands and Config Side by Side

Let's look at what a fresh project looks like in each approach. The bootstrapping difference is subtle but tells you a lot about what you're signing up for.

// Expo managed (SDK 52)
npx create-expo-app@latest my-app --template blank-typescript
cd my-app
npx expo start

// Bare React Native (0.76)
npx @react-native-community/cli@latest init MyApp --version 0.76
cd MyApp
# iOS setup
bundle install && cd ios && bundle exec pod install && cd ..
npx react-native run-ios

The Expo path takes about 90 seconds. The bare React Native path requires Ruby, CocoaPods, a valid Xcode CLI tools install, and sometimes an hour of debugging native build errors before you've written a single line of app code. That's not an exaggeration — it's a known onboarding pain point the React Native team has been fighting for years.

That said, if you're already comfortable with native tooling and you know upfront that you'll need deep native integration, starting bare saves you from ejecting later. Ejecting mid-project is manageable but it's not zero effort.

Performance in 2026: New Architecture Changes Things

React Native 0.76 shipped the New Architecture as the default. This means JSI (JavaScript Interface), the Fabric renderer, and the TurboModule system are all on by default. The old async bridge — the one responsible for most of React Native's historical jank — is gone for new projects.

Expo SDK 52 is built on React Native 0.76, so you get all of this in managed workflow too. The performance gap between Expo and bare React Native that people cited two or three years ago essentially doesn't exist for new projects. Both compile to the same native views, both run on the same JS engine (Hermes by default).

Where bare React Native still wins is in fine-grained performance control. You can configure Hermes settings, strip unused native modules from the bundle, and tune Gradle build variants more aggressively. For apps shipping to millions of users where every 50ms matters, bare gives you more levers. For most apps — honestly — you won't notice the difference.

Does your app actually need sub-16ms frame times everywhere, or does it need to ship in Q1? That's the real question to answer before obsessing over architecture choices.

EAS Build and Over-the-Air Updates vs Your Own CI Pipeline

One area where Expo genuinely pulls ahead is deployment infrastructure. EAS Build handles iOS and Android builds in the cloud, which means you don't need a Mac to ship to the App Store. For small teams or solo developers, this is enormous. A Mac Mini M4 is still $600 and macOS CI minutes on GitHub Actions run $0.08/minute — costs add up fast.

EAS Update enables over-the-air JavaScript updates. Ship a bug fix or new screen without going through App Store review. The constraint is that OTA updates can only change your JS bundle and assets — no native code changes. But the majority of day-to-day product iteration is JS changes, so this covers a lot of ground.

With bare React Native, you own your CI. That's either Fastlane, Bitrise, GitHub Actions with a macOS runner, or some custom pipeline. More control, more maintenance. If your team already runs a solid CI setup — maybe you're also shipping a web app with similar infrastructure, like something built on Next.js vs Remix — then the overhead is shared and less painful.

For most indie developers and early-stage startups, EAS is the right call. The $99/year Apple Developer fee is already painful — paying $0.08/minute on top for your own CI when EAS exists for free (with fair usage limits) is hard to justify.

When to Pick Bare React Native Over Expo

There are genuine cases where you should skip Expo entirely or eject early. The clearest one: you're integrating a proprietary native SDK that ships as a .xcframework or .aar file with no JavaScript wrapper. Healthcare apps using specialized Bluetooth hardware, fintech apps with specific security modules, enterprise apps talking to proprietary device firmware.

Another case: your app requires a custom native renderer or deep OpenGL/Metal work. Games, AR experiences, anything touching the GPU directly. Expo's abstraction layer adds overhead here that you might not want.

Team composition matters too. If your team includes iOS and Android engineers who are comfortable in Xcode and Android Studio, the Expo abstraction might feel like friction rather than help. They'll want to reach into native code directly, and managed workflow fights that instinct.

Finally, consider app size constraints. Expo managed workflow ships a larger binary because the runtime includes the full Expo SDK even if you only use three modules. With bare React Native you can do more aggressive tree-shaking of native code. Not always a dealbreaker — iOS App Store and Google Play both have reasonably generous size limits — but worth knowing.

Sharing Code With Your Web Stack

Here's a pattern worth thinking about: React Native with Expo Router (the file-based routing system Expo ships) can share significant logic with a Next.js web app. Same hooks, same context providers, same API client code. You do need separate UI components — React Native views aren't DOM elements — but business logic, state management, and data fetching are all shareable.

If you're looking at running a React component library across both web and mobile, best-free-ui-frameworks-react has a solid breakdown of which libraries support this. Empire UI is web-first, built on Tailwind, so it's not a direct fit for React Native — but if your web app uses Empire UI components and your mobile app needs matching design tokens (colors, spacing, type scale), you can absolutely extract those tokens and apply them in your StyleSheet.create() calls.

// Shared design tokens — works in both web (Tailwind) and React Native
export const tokens = {
  colors: {
    primary: '#6366f1',
    surface: 'rgba(255,255,255,0.08)',
    border: 'rgba(255,255,255,0.15)',
  },
  spacing: {
    xs: 4,
    sm: 8,
    md: 16,
    lg: 24,
    xl: 32,
  },
  radius: {
    sm: 6,
    md: 12,
    lg: 20,
  },
} as const;

// In React Native component
const styles = StyleSheet.create({
  card: {
    backgroundColor: tokens.colors.surface,
    borderColor: tokens.colors.border,
    borderWidth: 1,
    borderRadius: tokens.radius.md,
    padding: tokens.spacing.md,
    gap: 8, // 8px gap matches your web grid
  },
});

If you're also wrestling with tooling choices for the web side of this stack, vite-vs-nextjs covers the bundler and framework tradeoffs in detail. Cross-platform product development involves a lot of these kinds of decisions stacking up.

The 2026 Verdict: A Practical Decision Framework

Start with Expo managed workflow unless you have a specific reason not to. This used to be controversial advice — Expo had real limitations that pushed developers toward bare React Native faster than they'd like. SDK 52 and EAS have closed most of those gaps. You can build genuinely production-grade apps in managed workflow now.

Reach for bare React Native (or bare workflow after ejecting from Expo) when: you have confirmed native module requirements that aren't in the Expo SDK, your team is native-heavy and wants direct access to platform APIs, or you need maximum control over binary size and build configuration.

Don't over-engineer the decision upfront. Ejecting from Expo managed to bare is a documented process that takes a few hours, not days. Most apps never need to eject. Start fast, validate your product, eject if the ceiling actually hits you.

The cross-platform mobile space in 2026 is in a genuinely good place. React Native 0.76's New Architecture removes the old async bridge bottleneck. Expo SDK 52 makes the developer experience fast and approachable. You're not trading performance for convenience the way you used to be. The comparison that actually matters now is React Native vs Flutter — and that's a different article.

FAQ

Can I use Expo SDK modules in a bare React Native project?

Yes. Most Expo SDK packages (expo-camera, expo-notifications, expo-location, etc.) work fine in bare workflow and even in plain React Native projects that don't use Expo at all. You install them via npm/yarn, run pod install for iOS, and they link like any other native module. The main thing you lose is automatic configuration — in managed workflow, Expo handles native setup automatically via config plugins.

Is Expo Go still useful in 2026 or should I be using a development build?

Expo Go is still useful for quick prototyping with the standard SDK, but development builds (via npx expo run:ios or EAS Build with the development profile) are what you want for real projects. Development builds include your custom native code and config plugins, so you're testing the actual app rather than a sandboxed version. The Expo team has been nudging people toward development builds for a couple of years now.

Does Expo support the React Native New Architecture (Fabric + TurboModules)?

Yes, as of Expo SDK 52 (built on React Native 0.76), the New Architecture is on by default. All official Expo SDK modules support it. Third-party modules are the variable — if you're using a community module that hasn't been updated to support JSI and Fabric, you may hit compatibility issues. Check the library's repo for 'new architecture' support before committing.

How does EAS Build pricing work for small teams?

EAS has a free tier that includes 30 builds per month, which is enough for small teams and side projects. The free tier builds run on shared infrastructure and are slower than priority queues. Paid plans start at $99/month for Production tier, which gives you more concurrent builds and faster machines. For comparison, a GitHub Actions macOS runner costs $0.08/minute — a typical iOS build takes 15-25 minutes, so $1.20-$2.00 per build. EAS free tier often wins on cost for low-volume shipping.

Can I use TypeScript with Expo and what's the setup like?

TypeScript is supported out of the box in Expo. Running npx create-expo-app --template blank-typescript gives you a fully configured TypeScript project with tsconfig.json, path aliases, and type definitions for the Expo SDK. You don't need to configure Babel or Metro manually for TypeScript — Expo handles that. The SDK types are well maintained and generally accurate.

What's the difference between expo-router and React Navigation in 2026?

Expo Router is a file-system-based routing layer built on top of React Navigation. If you've used Next.js or Remix, the pattern will feel familiar — files in the app/ directory become routes automatically. React Navigation is the underlying library that handles the actual navigation stack, tab bars, and drawer navigators. You can use React Navigation directly without Expo Router. Expo Router is the recommended approach for new Expo projects because it also enables universal routing across web and native with the same file structure.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

TypeScript vs JavaScript for React UI: The Case for Strict ModeTypeScript vs JavaScript in 2026: Is TS Still Worth the Setup?CSS Masonry Layout: Native Grid masonry Value vs JavaScriptReact UI Components Complete Reference: 60+ Patterns with Code