Building Production Mobile Apps with React Native and Expo in 2026

Five years ago, choosing React Native for a production app required genuine courage. The tooling was immature, Expo's managed workflow was limited, and "ejecting" was a rite of passage almost everyone eventually endured. Today, the stack is different. React Native's new architecture is shipping in production, Expo's managed workflow covers the vast majority of what business apps need, and EAS (Expo Application Services) has replaced the manual app store submission process with a CI/CD pipeline that actually works.
Here's what the stack looks like in 2026 and how we use it for client apps.
What Expo Adds on Top of React Native
React Native is the framework. Expo is the tooling and SDK layer that sits on top of it.
Without Expo, a React Native project is a relatively bare-bones setup. You manage your own native build configurations, set up your own CI, integrate device APIs one by one, and configure app signing manually. This is workable for teams with dedicated iOS and Android engineers — but most app projects don't need that complexity.
Expo SDK. A set of JavaScript APIs for device hardware and OS features: camera, file system, notifications, location, sensors, biometric authentication, contacts, calendar, in-app browser, haptics, media library, and more. Most business apps need a subset of these, and the Expo SDK versions are tested to work together. In 2026, Expo SDK 52 covers the overwhelming majority of what a business app will need.
Managed Workflow. In managed workflow, you don't touch the native iOS (/ios) or Android (/android) project directories. Expo manages the native layer based on your app.json and app.config.js configuration. You work entirely in JavaScript/TypeScript. This is a significant productivity advantage — you don't need Xcode or Android Studio to develop, your configuration is version-controlled, and onboarding new developers is fast.
EAS Build. Expo's cloud build service. You run eas build and it produces a signed .ipa (iOS) or .aab (Android) in the cloud, without needing Xcode locally. Builds can be triggered from CI. Different build profiles (development, preview, production) are configured in eas.json. For iOS, EAS handles provisioning profiles and certificates, which is historically one of the most painful parts of iOS development.
EAS Submit. Automates App Store Connect and Google Play Console submissions. After eas build, you run eas submit and the binary is uploaded directly to the relevant store for review. Combined with EAS Build, this eliminates most of the manual friction in the deployment process.
OTA Updates. Over-the-air updates via expo-updates allow you to push JavaScript bundle updates to users without going through App Store review. This is genuinely powerful for bug fixes and non-native-layer changes. A fix can be deployed and live on user devices within minutes. This is within App Store guidelines as long as you're not changing the core functionality of the app.
Expo Router. File-system-based navigation for React Native. Routes in app/ map to screens, the same mental model as Next.js for web apps. Deep linking and web support (if you're building a universal app) are handled automatically. Typed routes give you TypeScript safety on navigation. This is now our default navigation approach for new projects.
What "Ejecting" Means and When You Need To
"Ejecting" means leaving Expo's managed workflow and taking ownership of the native iOS and Android project directories. Once you eject (or use "bare workflow" from the start), you have full control over the native layer — but you also have full responsibility for it.
In the current Expo ecosystem, ejecting is less common than it used to be. Expo's config plugins allow many native customizations to be applied to the managed build without ejecting. If you need to, say, add a custom native module, you can often write a config plugin that modifies the native projects at build time, rather than managing those files manually.
Cases where you genuinely need bare workflow today:
- A native module exists that has no Expo equivalent and no config plugin
- You need very specific native build settings that config plugins can't express
- You're integrating with a proprietary SDK that only ships as a native library (e.g., certain Bluetooth peripheral SDKs, custom hardware drivers)
For the apps we build — SaaS tools, marketplaces, client portals, service apps — we stay in managed workflow. If bare workflow becomes necessary mid-project, it's an explicit decision with a rationale, not a surprise.
Performance in Production: Honest Assessment
React Native's performance reputation comes mostly from the old architecture. The "bridge" — the async message-passing layer between JavaScript and native — was a real bottleneck for animations, gestures, and anything that needed synchronous communication between the two sides.
The new architecture (JSI, Fabric renderer, TurboModules) eliminates the bridge. JavaScript can call native code synchronously via JavaScript Interface. UI updates via Fabric happen on the main thread. This has been shipping in React Native since 0.76 (released late 2024) and is the default in Expo SDK 52.
In practice, for business apps — navigation, data fetching, forms, lists, notifications, media viewing — performance with the new architecture is genuinely good. You're not going to notice a meaningful difference from native for these use cases.
Where React Native still has limits:
- Complex animations at 60/120fps. React Native Reanimated runs on the UI thread and handles most animation needs, but very complex scenes with many animated elements simultaneously are harder than in SwiftUI or Jetpack Compose.
- Heavy image processing or real-time video manipulation. If your app is doing frame-by-frame processing, custom camera filters, or augmented reality, you're better off with native.
- Deeply custom platform gestures. Advanced gesture handling is achievable with React Native Gesture Handler, but native feels more natural for complex multi-touch interactions.
For the apps most founders actually build, none of these are constraints.
Navigation with Expo Router
Prior to Expo Router, React Native navigation was managed by React Navigation — a JavaScript library that's excellent but requires manual route definition and link handling. Expo Router brings file-system routing to mobile, which changes the development experience significantly.
A file at app/(tabs)/profile.tsx becomes the /profile route accessible via the tab navigator. A file at app/orders/[id].tsx becomes a dynamic route for order detail screens. Layouts are composed, deep links work automatically, and you get TypeScript-typed navigation throughout.
We use Expo Router as our default navigation approach. The mental model is familiar to web developers, onboarding is faster, and the automatic deep link handling saves meaningful time.
Real Limitations You Should Know About
- Over-the-air updates have limits. OTA updates only update the JavaScript bundle. Changes that require a new native binary — new native modules, updated native dependencies, app permission changes — still require a full build and store submission.
- SDK compatibility windows. Expo SDKs have compatibility windows. If you're several major SDK versions behind, upgrading is a real project. We recommend staying within 1–2 major versions of the latest SDK and doing annual SDK upgrades as part of maintenance.
- Some APIs still have rough edges. Background processing, certain Bluetooth scenarios, and video recording have historically been the areas where Expo's managed workflow shows its limits most clearly. These work, but edge cases require more debugging than pure native implementations.
- Build times. EAS Build is cloud-based, and iOS builds in particular can take 20–40 minutes. Compared to local Xcode builds this is slower, but you also don't need a Mac on every developer's desk.
Adding React Native to an Existing Web Product
If you already have a web application and want to add a mobile companion app, React Native with Expo is almost always the right choice. The shared mental model with React web, the ability to reuse business logic, and the single codebase for both iOS and Android make it the most practical path for teams with existing web infrastructure.
How We Use It for Client Projects
Our default stack for a new mobile app in 2026:
- Expo SDK 52, managed workflow
- Expo Router for navigation
- TypeScript throughout
- React Query (TanStack Query) for server state
- Zustand for local client state (when needed)
- EAS Build + EAS Submit for CI/CD
- expo-updates for OTA patches
- RevenueCat for in-app subscriptions (when applicable)
- Sentry for error monitoring
This stack ships fast, is maintainable by any React Native developer, and stays close enough to the Expo ecosystem that we get SDK updates and tooling improvements without significant migration work.
After your app is built, getting it through App Store review is the next major milestone — knowing the common rejection reasons before you build saves rework.
See how we approach mobile app projects or learn what technical discovery produces before we build.
For the full picture of what goes into a mobile app from idea to launch, see our complete mobile app development guide.
Related Posts

Mobile App Development: The Complete Guide for Non-Technical Founders
Everything you need to know before building a mobile app — platform choice, costs, timelines, App Store approval, subscriptions, and finding the right team.

Why We Build SaaS Web Apps with Next.js (And When We Don't)
Next.js has become the default for production SaaS apps. Here's why we use it, what problems it solves, and the cases where something else makes more sense.