TypeScript + React + business logic.
Screens, navigation, state, API calls, data models, validation, styling, animations. Written once in TS + React, runs the same on both platforms.
An Expo-Router-first React Native practice shipping iOS and Android from a single TypeScript codebase with EAS OTA updates, signed deployments, and a naming-names approach to when Expo is wrong.
React Native in 2026 ships 92 percent of its code once and runs it on both iOS and Android through platform-specific native bridges for the remaining 8 percent. The central discipline is knowing which 8 percent needs to live on each branch: CoreLocation vs Android Camera2, StoreKit vs Play Billing, HealthKit vs Health Connect. Getting the branch boundary right is the difference between an app that feels native on both platforms and an app that feels like a compromise on both.
Screens, navigation, state, API calls, data models, validation, styling, animations. Written once in TS + React, runs the same on both platforms.
CoreLocation, CoreBluetooth, HealthKit, StoreKit, specific WidgetKit or Live Activities work. Either via an Expo module or, for deep work, native Swift code.
Camera2, Play Billing, Android Keystore, specific Health Connect integration, background services. Via Expo module or Kotlin for deep work.
The old "Expo cannot do X" argument is largely outdated. Expo with dev client plus the Expo Modules API covers 85 percent of what used to force bare workflow. We still use bare for deep native work: specialized Bluetooth, custom camera pipelines, background audio processing. For the rest, Expo's velocity, OTA updates, and EAS Build pipeline win.
| dimension | Expo (managed + dev client) | Bare workflow |
|---|---|---|
| setup time | minutes | days (Xcode + Android Studio + signing) |
| OTA updates | EAS Update, built-in | CodePush or self-hosted |
| build pipeline | EAS Build (cloud) | Fastlane + local Xcode/Android |
| custom native code | via Expo Modules API | direct Swift/Kotlin |
| team ramp-up | React devs productive in days | native expertise required |
| best for | 85% of modern RN work | deep native integration, specialized hardware |
EAS Update ships JavaScript bundle changes directly to users without a store review. Bug fixes and content changes reach users in minutes. Native changes still need a store submission. We configure channel-based rollouts: canary for early testers, beta for the opt-in beta channel, production for everyone else. Rollbacks happen from the command line and are live within 5 minutes.
Signed iOS and Android binaries built in the cloud. Credentials managed by EAS, rotate without touching local machines. Production builds typically 20-40 minutes.
JS bundle updates over the air, reach users in minutes not days. Channels for staged rollouts. Rollback from CLI if issues surface.
App Store and Play Store submissions from CLI. Release notes, metadata, screenshots handled declaratively in EAS config.
| metric | target | measured on |
|---|---|---|
| cold start to first screen | < 1.8s | mid-tier Android, iPhone 12 |
| warm start | < 600ms | both platforms |
| list scroll fps | 60 fps | FlashList or Reanimated 3 |
| time to interactive | < 2.5s | first meaningful interaction |
| crash-free users | > 99.7% | Sentry, 30-day rolling |
Companion app for a Shopify subscription brand. Order history, skip + swap flows, loyalty tier, push campaigns. Expo + Expo Router + TanStack Query. 12 weeks to production, 4.7 App Store rating, 4.6 Play Store.
Field technician app for a B2B service company. Works offline on site, syncs when network returns, signature capture, barcode scan, photo upload queue. WatermelonDB for offline store, Expo Modules API for custom barcode scanner. 18 weeks.
2 weeks. Expo vs bare, native surface, store readiness. Refundable.
10-16 weeks. 15-25 screens, auth, push, OTA, store submit.
14-22 weeks. Native modules, offline, IAP, deep links.
16-26 weeks. iOS or Android native → React Native.
Expo (managed with dev client) for 85 percent of modern React Native projects. The dev client workflow lets you add most native modules Expo does not include out of the box, so the old objection of 'Expo cannot do X' is outdated in 2026. Bare workflow only when you need deep native work that cannot live behind an Expo config plugin: custom Bluetooth stacks, specialized camera pipelines, background audio processing, or hardware-specific integrations. Team size and native expertise also matter. For teams of 2 to 4 engineers shipping a standard app, Expo wins. For teams with dedicated iOS and Android engineers already in place doing specialized native work, bare may fit.
US and UK senior React Native engineers are $145 to $200 per hour at boutique agencies; Indian senior engineers are $85 to $140 per hour. A standard React Native MVP with Expo Router, auth, push notifications, OTA updates, and store submission runs 10 to 16 weeks. A full production build with native module bridges, offline sync, in-app purchases, and deep links runs 14 to 22 weeks. A rewrite from native iOS or Android runs 16 to 26 weeks depending on feature count. A 2-week audit is refundable. Scoped quote in 48 hours.
Over-The-Air (OTA) updates via EAS Update let you ship JavaScript bundle changes directly to users without an App Store or Play Store review. JS-only changes (bug fixes, content updates, feature flag flips, new screens that use existing native modules) reach users in minutes instead of 1 to 7 days. Native changes (new modules, permission changes, icon changes) still require a store submission. OTA matters because it decouples JS velocity from store review cycles, lets you roll out fixes same-day, and supports channel-based staged rollouts (beta, canary, production).
Three paths. One, use an existing Expo module (expo-camera, expo-notifications, expo-location cover most needs). Two, use a community module with an Expo config plugin (most major libraries have these now). Three, write a custom Expo module when the need is genuinely unique. The Expo Modules API in 2026 is mature enough to write Swift and Kotlin native code inside an Expo project, so 'we need custom native code' is no longer a reason to leave Expo. Only when the native work is large enough to justify dedicated iOS and Android engineers do we recommend bare.
Yes. For simple offline (cached API responses, offline queue of pending writes), TanStack Query with persistent cache via AsyncStorage or MMKV handles most cases. For full offline-first (collaborative editing, complex sync, conflict resolution), WatermelonDB or Legend State plus a custom sync layer is the pattern we ship. For the hardest case (offline-first with CRDTs or operational transforms), Replicache or PowerSync via a managed backend. Offline-first adds 4 to 8 weeks to the scope; we map the offline requirements in week one.
expo-notifications for the client side; Firebase Cloud Messaging (FCM) on Android and APNs on iOS as the delivery providers. On the backend we integrate with a provider: Expo Push (for small volume), OneSignal or Customer.io (for marketing and rich notifications), or direct APNs/FCM via a backend service for full control. Critical UX details: permission prompts are shown at the right moment (not on app launch), not-opted-in state is handled, silent push for background data is measured and respected by iOS throttling rules.
EAS Submit handles both stores from command line. Before first submit, we set up App Store Connect and Google Play Console accounts under your organization, configure signing certificates (managed credentials via EAS), write store listings, create screenshots in every required size (we have a Figma template for this), prepare privacy labels and data safety forms. First submit typically takes 1 to 3 days of review on Apple, same-day on Google. We run a dry-run against the review guidelines internally before submitting. First rejection rate is rare but handled by same-week fix and resubmit.
You do, fully. GitHub repository under your organization. Apple Developer Program membership and Google Play Developer account under your legal entity. EAS account and signing certificates under your EAS organization with DH engineers as named collaborators removable any time. Push notification provider (Expo Push, OneSignal) under your billing. On exit: repository transferred, credentials rotated, store access handed off, 30-day support tail. No lock-in through signing, tooling, or vendor choice.
Two weeks. Expo vs bare, native module surface, store readiness. Refundable against any engagement that follows. Scoped quote in 48 hours.