React Native Deep — Bridgeless New Architecture, Expo, and the JS-Native Stack

React Native (RN) is the longest-running JavaScript-to-native mobile framework still under active platform-vendor development. Open-sourced by Facebook in 2015, it pioneered the “JavaScript writes UI; native renders it” pattern that Flutter, Fuchsia, and Lynx have since iterated on. The 2024-2026 cohort of RN releases — 0.74, 0.75, 0.76 — completed the multi-year New Architecture migration: Fabric renderer, TurboModules, JSI, Hermes-default, and (in 0.76) Bridgeless mode by default. Expo SDK 50-53 paralleled the changes, becoming the recommended workflow even for what used to be “bare” projects. This note covers the runtime architecture, the canonical ecosystem (Expo, React Navigation, Reanimated, FlashList, MMKV), the deployment surface (EAS Build, code-signing, OTA updates), and the engineering realities — what works production-scale, what’s brittle, who’s using it, and who’s left.

See also

1. Architecture: legacy bridge vs New Architecture

1.1 The legacy bridge (2015-2024)

The original architecture had three threads: the JS thread (running React reconciler), the native main/UI thread (rendering), and the shadow thread (Yoga layout). Communication between JS and native happened through an asynchronous serialised JSON message queue (the Bridge). Every call — props update, event dispatch, native module method — was serialised to JSON, posted across threads, deserialised, dispatched. The model was correct but slow: large lists, animations driven from JS, and any high-frequency native callback hit serialisation cost.

Symptoms in production: stuttery animations when state updated from JS, slow startup as the entire JS bundle had to be parsed before any UI rendered, race conditions when JS and native diverged on view state.

1.2 The New Architecture (2019-2024 rollout)

Four interrelated rewrites:

  • JSI (JavaScript Interface). A lightweight C++ API that lets any JS engine (Hermes, JSC, V8) expose host objects directly to JavaScript. Replaces JSON serialisation with synchronous C++ calls. Native modules can hold JSI references and invoke JS callbacks without bridge round-trips.
  • TurboModules. The new native-module system built on JSI. Modules are lazy-loaded on first call (vs eager-loaded at startup in the legacy bridge), reducing startup time. Codegen from TypeScript/Flow specs generates the C++ glue.
  • Fabric. The new renderer. View hierarchy is a C++ shadow tree shared across threads; React’s reconciliation produces shadow-tree mutations that Fabric applies synchronously on the UI thread. Eliminates the JS-thread / UI-thread divergence window. Supports synchronous layout reads (measureInWindow returns immediately), concurrent React features, and Suspense.
  • Bridgeless mode. The final piece: removes the legacy bridge entirely. Even the runtime initialisation skips bridge setup. Default in RN 0.76 (October 2024) for new projects; existing projects opt in via newArchEnabled=true in gradle.properties and :hermes_enabled => true in Podfile.

1.3 Hermes

Hermes is Meta’s JavaScript engine optimised for RN. Ahead-of-time bytecode compilation: JS is compiled to bytecode at build time, shipped as .hbc files, and loaded directly at runtime — no parse cost. Generational mark-sweep GC tuned for short-lived React render closures. Smaller memory footprint than JSC (Apple’s JavaScriptCore, the iOS default before Hermes). Hermes has been default on Android since RN 0.70 (2022) and on iOS since 0.71 (2023); 0.76 made it the only supported engine for new projects.

Hermes is not fully ES2023-compliant — Proxy support is partial, BigInt was added late, some regex features are missing. The Hermes team tracks a compatibility table; the gap has narrowed substantially since the 2022 push toward Hermes for Web and Static Hermes (experimental statically-typed subset).

1.4 Threading model

  • JS thread. Runs React reconciler and most user code.
  • UI/main thread. Rendering, gesture handling.
  • Shadow thread (legacy) / Worklet threads (Reanimated 3). Layout computation; in the new architecture this becomes a C++ background thread.
  • Background threads. Network, image decoding (managed by native modules).

With JSI + Fabric, calls between threads are synchronous in C++; the cost is microseconds, not milliseconds.

2.1 What Expo is in 2026

Expo is no longer just a “managed” sandbox you could outgrow. Since SDK 50 (2024), Expo SDK is the recommended starting point even for apps that need custom native code, thanks to:

  • Continuous Native Generation (CNG). expo prebuild regenerates the ios/ and android/ directories from your app.json config + installed config plugins on every build. Native code is treated as a build artifact, not source.
  • Expo Modules API. A Swift/Kotlin DSL for authoring native modules that target the New Architecture directly, with TypeScript spec generation. Replaces the legacy bridge-based module pattern.
  • EAS Build. Cloud builds for iOS and Android, eliminating the need for a local macOS for iOS builds.
  • EAS Update. Over-the-air JavaScript bundle updates, replacing the deprecated CodePush.
  • EAS Submit. Automated submission to App Store Connect and Play Console.

Expo SDK is versioned alongside RN: SDK 50 → RN 0.73, SDK 51 → 0.74, SDK 52 → 0.76, SDK 53 → 0.77 beta. The “bare workflow vs managed workflow” distinction is dead; in 2026 there are just Expo apps with varying levels of config-plugin and native-code customisation.

2.2 Expo Router

File-based routing built on React Navigation v7. The app/ directory mirrors the URL structure: app/index.tsx, app/profile/[id].tsx, app/(tabs)/feed.tsx. Layouts via _layout.tsx; route groups via (group)/; dynamic routes via [param]. Deep links work automatically: a URL myapp://profile/123 maps to app/profile/[id].tsx. Server-side rendering and static export via expo export enable Universal apps (iOS + Android + Web from one codebase).

Expo Router 3 (mid-2024) added typed routes (href parameter is type-checked against the app/ directory at compile time via the experimental: { typedRoutes: true } flag) and stable Tabs/Stack layouts.

2.3 Config plugins

Config plugins are Node functions that mutate the iOS Info.plist, AndroidManifest.xml, Podfile, Gradle files etc. during expo prebuild. Example: expo-camera’s plugin adds the camera usage description string and required permissions. Community plugins exist for hundreds of third-party SDKs; for any SDK without one, you write a small plugin or eject the native code.

3. Navigation

3.1 React Navigation v7

React Navigation has been the de facto routing solution since 2017 (with v1 dating to its Wix-Navigator era). v7 (2024) added typed routes, performance improvements via the New Architecture, and a unified Stack/Tab/Drawer API. Navigators:

  • Native Stack. Wraps UINavigationController (iOS) and Fragment (Android). True native push animations and gestures.
  • JS Stack. Cross-platform implementation in JS + Reanimated. Used when native stack’s customisation limits matter.
  • Bottom Tabs, Material Top Tabs, Drawer. Standard patterns.

Expo Router 3+ wraps React Navigation v7 with the file-based API; underneath, the same primitives.

Linking.openURL, Linking.addEventListener. For deep links to work outside the app: iOS Universal Links (requires apple-app-site-association on the domain) and Android App Links (requires assetlinks.json). Expo’s expo-router handles registration automatically.

4. State management

The RN ecosystem has cycled through libraries; the 2026 status:

  • Zustand. Minimal, hook-based. Recommended default for new apps; ~3 KB; no boilerplate; selector subscriptions for performance.
  • Jotai. Atom-based, fine-grained. Good for derived state.
  • Redux Toolkit. RTK Query for data fetching + caching. Heavyweight; declining for new apps but dominant in legacy.
  • TanStack Query (React Query). Server-state caching. Almost universal — practically every RN app fetching from a REST/GraphQL API uses it.
  • Context API. Built-in; fine for small apps and theme/locale propagation.
  • Recoil. Facebook’s atom library; effectively abandoned (last release Feb 2023); avoid for new code.
  • MobX, MobX-State-Tree. Observable-based; still in use for some larger apps.

Pattern: TanStack Query for server state, Zustand or Context for client state.

5. Styling

RN’s built-in StyleSheet.create({...}) returns an opaque ID and validates style props at runtime. It is fine for small apps but lacks design tokens, variants, and theming primitives. Community solutions:

  • NativeWind 4.x. Tailwind CSS for RN. v4 (2024) added CSS-feature parity (cascade, media queries, container queries via simulator). Recommended for teams already invested in Tailwind.
  • Tamagui. Compile-time-optimised styles. Provides themed, animated, performant components; strong design-system support.
  • Restyle (Shopify). Theme-driven typed style props.
  • Unistyles 2.0. Multi-platform styling with media-query and breakpoint support; New-Architecture-native.
  • Dripsy. Theme-UI-inspired; less active.
  • Emotion, styled-components. CSS-in-JS; runtime cost makes them less popular than Tamagui or NativeWind for new apps.
  • Stylo. Variant-heavy styling DSL.

Pattern: NativeWind for tailwind teams, Tamagui for design-system-first teams, plain StyleSheet for small apps.

6. Animations and gestures

6.1 Reanimated 3

Reanimated (Software Mansion) is the standard animation library. v3 (2022; v3.6+ in 2024-25 with the New Architecture) provides:

  • Worklets. JS functions that compile to a separate JS context running on the UI thread. The 'worklet' directive marks a function; the Reanimated Babel plugin extracts it.
  • Shared values. useSharedValue(0) returns a mutable container readable from worklets and the JS thread; mutations on the UI thread re-render only the worklet-driven views.
  • withTiming / withSpring / withDecay. Animation primitives that run entirely on the UI thread.
  • Layout animations. entering/exiting props on Animated views with FadeIn, SlideInRight, custom presets.
  • Shared Element Transitions. Cross-screen morph animations.

Reanimated 3 + Gesture Handler 2 replace the legacy Animated API (still shipped but discouraged for new code).

6.2 React Native Gesture Handler 2

Hardware-accelerated gestures on the UI thread. Pan, pinch, rotation, long-press, swipe, fling — all without JS thread involvement. Required by React Navigation and most modern UI libraries. v2.x is the New Architecture-compatible version.

6.3 Skia (Shopify)

react-native-skia exposes Google’s Skia rendering library to RN as a Canvas component. 2D + 3D graphics, custom shaders, image filters, video processing. Used in production by Shopify (Shop app), Rainbow Wallet. Enables Lottie-level animations without the Lottie library.

6.4 Lottie, LinearGradient, SVG

  • Lottie (react-native-lottie). Plays After Effects animations exported via Bodymovin.
  • react-native-linear-gradient. Linear/radial gradient backgrounds.
  • react-native-svg. SVG rendering; the substrate for many icon libraries (react-native-vector-icons, lucide-react-native).
  • SafeAreaView (react-native-safe-area-context). Handles notches, dynamic islands, navigation bars.

7. Lists

7.1 FlashList (Shopify)

@shopify/flash-list replaces FlatList for production-grade lists. Uses RecyclerView-like view recycling on both platforms; supports estimatedItemSize for header-less layouts; handles dynamic content much better than FlatList. Used by Shopify, Discord, Bluesky. The performance gap is dramatic on lists >100 items.

7.2 FlatList, SectionList, VirtualizedList

Built-in. Adequate for small lists; large lists (100+ items, complex item rendering) hit performance walls.

7.3 LegendList, Tanstack Virtual

Newer entrants competing with FlashList. LegendList (LegendApp, 2024) claims faster scroll perf via tighter virtualisation; less battle-tested.

8. Persistence

8.1 MMKV (Tencent)

react-native-mmkv (Marc Rousavy) wraps Tencent’s MMKV key-value store. Memory-mapped file I/O; synchronous reads and writes (no Promise); ~30× faster than AsyncStorage. Used as the default storage for Zustand persistence, TanStack Query persistence, and ad-hoc preferences. Encryption supported via per-instance keys backed by Keystore/Keychain.

8.2 AsyncStorage

The legacy KV store. Asynchronous; slow; deprecated for performance-sensitive use cases. Still in use for back-compat.

8.3 SQLite-backed libraries

  • WatermelonDB. Reactive ORM on top of SQLite; uses lazy-loading and observables to avoid loading entire tables. Excellent for chat/feed apps with >10K rows. Used by Nozbe, Steady.
  • Op-SQLite (Op-Engineering). High-performance SQLite wrapper with JSI; replaces react-native-quick-sqlite (which is now archived). Synchronous + async APIs.
  • expo-sqlite. Expo-provided SQLite wrapper; New Architecture-ready.

8.4 Realm React Native

MongoDB Realm. Object database with sync to MongoDB Atlas Device Sync. Cross-platform; popular for offline-first apps. Mindshare declining since MongoDB’s 2022 strategic pivot away from Realm marketing, but still production-stable.

8.5 react-native-keychain

Wraps iOS Keychain and Android Keystore. Used for storing tokens, biometric-protected secrets.

9. Native modules

9.1 Autolinking

Since RN 0.60 (2019), installing a native module via yarn add foo + cd ios && pod install automatically registers it — no manual Linking in Xcode/Android Studio. The community CLI introspects the react-native.config.js files in each package.

9.2 Expo Modules API

The modern way to write native modules. Swift DSL on iOS:

public class MyModule: Module {
    public func definition() -> ModuleDefinition {
        Name("MyModule")
        Function("hello") { (name: String) -> String in
            "Hello, \(name)"
        }
        AsyncFunction("download") { (url: URL) async throws -> String in
            ...
        }
    }
}

Kotlin DSL on Android. Codegen produces TypeScript bindings. New Architecture-native; no bridge.

9.3 Direct JSI modules

For peak performance (camera, video, ML inference), modules expose jsi::HostObject directly. Examples: VisionCamera (V3+), Reanimated, RN Skia. C++ glue is more complex than Expo Modules but gives microsecond-latency calls into JS.

9.4 Codegen

For Fabric components and TurboModules, RN’s codegen (driven by TypeScript or Flow spec files in src/specs/) generates the C++ shim. Required for components using the new architecture’s view registration system.

10. Networking and data

  • Fetch API. Built-in.
  • Axios. Common HTTP wrapper.
  • TanStack Query. Cache + retry + invalidation; production default.
  • SWR. Vercel’s alternative; less common in RN.
  • Apollo Client + urql + ferry. GraphQL.
  • WebSocket. Built-in WebSocket global.
  • react-native-mqtt, socket.io-client. Real-time messaging.
  • Server-Sent Events (SSE). Polyfilled via react-native-sse.

11. Deployment: EAS Build, OTA updates

11.1 EAS Build

Expo Application Services Build (eas.dev) runs cloud-hosted iOS and Android builds. Configuration in eas.json; build profiles (development, preview, production) define environment variables, distribution channels, and signing credentials. Free tier (~30 builds/month), paid tiers up to dedicated build machines. Local builds via eas build --local for teams with self-hosted CI.

iOS code-signing is handled automatically: EAS holds the App Store Connect API key, fetches/generates certificates and provisioning profiles. Android: EAS generates/holds the keystore unless you upload your own. The lock-in concern (Expo holds your credentials) is partially mitigated by eas credentials for export and re-import.

11.2 EAS Submit

eas submit --platform ios uploads to App Store Connect; --platform android uploads to Play Console internal track. Wraps fastlane under the hood.

11.3 EAS Update

Over-the-air JavaScript bundle updates. eas update --branch production --message "fix" publishes a new bundle that apps fetch on startup. Channels (production, staging) and runtime versions (runtimeVersion in app.json) gate which builds receive which updates. Replaces CodePush (Microsoft App Center; Microsoft announced App Center retirement March 2025, sunset in 2026).

Apple’s review-bypass policy: OTA updates may not change advertised functionality or violate App Review; you can ship bug fixes and small UI tweaks but not entirely new features without a re-review. Expo Updates supports rollback (eas update --rollback-to-embedded) for emergency reverts.

11.4 Local builds and CI alternatives

  • Bitrise, Codemagic, GitHub Actions on macOS runners. All can build RN apps directly via npx expo prebuild && fastlane ios build.
  • App Center. Discontinuing — migrate off.

12. Production users (2024-2026)

Apps shipping React Native in production at scale:

  • Meta apps. Facebook (parts), Marketplace, Ads Manager.
  • Shopify. Shop, Shopify Mobile, POS Go.
  • Discord. Both iOS and Android.
  • Microsoft Office (mobile parts). Outlook (some flows), Microsoft Teams (web + RN parts), Xbox Game Pass.
  • Walmart, Tesla, Coinbase, Wix, Bloomberg, Pinterest, Mercari, Skype, Wendy’s, NerdWallet, Tableau, SoundCloud Pulse.
  • Bluesky. Their iOS + Android + Web apps share an RN/Expo Router codebase.

Apps that abandoned RN are widely cited:

  • Airbnb (2018). Public postmortem cited bridge cost for animations and mismatch between RN’s UI primitives and Airbnb’s design language. The article preceded the New Architecture by six years and many of the cited issues are now addressed.
  • Udacity (2017), Tipsi-tickets, others. Various reasons; usually team-skill or platform-specific feature blockers.

The 2018-2020 wave of “we left RN” posts was driven by the legacy bridge limitations the New Architecture has since fixed. New-architecture-era assessments (2024+) are more positive; Discord publicly committed to RN in 2024 after a multi-year evaluation.

13. Tooling

13.1 Metro

Metro is the JS bundler. Incremental, file-watching, supports tree-shaking (partially), CommonJS + ESM hybrid. Replaces Webpack for RN. Configuration via metro.config.js. Hermes bytecode generation happens after Metro bundling.

13.2 Babel and SWC

Babel transforms (JSX, TS, decorators, Reanimated worklet extraction) run during Metro bundling. Expo SDK 52 (2024) added optional SWC support for ~30% faster bundling on large apps; not default yet.

13.3 Flipper and the new debugger

Flipper (Meta’s debugger) was the canonical debugging tool through 2023; deprecated in favour of the new React Native DevTools (Chrome DevTools-derived, integrated with the Hermes inspector). React Native CLI 0.73+ ships the new debugger by default.

13.4 Reactotron

Third-party Electron app for inspecting state, network, async storage. Popular but partly displaced by React DevTools.

13.5 ESLint, Prettier, TypeScript

Standard JS tooling applies. RN templates ship tsconfig.json with strict mode and the react-native JSX runtime.

14. Cross-cutting concerns

14.1 Internationalisation

  • i18n-js, i18next. Translation key lookup.
  • react-i18next. React-specific bindings.
  • Format.js / react-intl. ICU MessageFormat-based pluralisation and gender.
  • Intl global (Hermes). Hermes 0.13 (2024) ships full Intl support; replaces polyfills for Intl.DateTimeFormat, Intl.NumberFormat, etc.

14.2 Accessibility

accessible, accessibilityLabel, accessibilityRole, accessibilityState, accessibilityActions props on every View. Maps to UIAccessibility on iOS, TalkBack semantics on Android. Compose-style auto-merging not present; explicit labels required on every interactive surface.

14.3 Push notifications

  • expo-notifications. Wraps APNs and FCM with a uniform API.
  • react-native-firebase/messaging. Direct FCM integration.
  • OneSignal, Notifee, Iterable, Braze. Marketing-friendly notification platforms.

iOS notification permissions via requestPermissionsAsync(); Android 13+ requires POST_NOTIFICATIONS runtime permission.

14.4 Authentication

  • Sign in with Apple, Google, Facebook. Via expo-apple-authentication, react-native-google-signin/google-signin, react-native-fbsdk-next.
  • Auth0, Clerk, WorkOS, Supabase Auth. SDK-driven OAuth flows.
  • Biometric. expo-local-authentication wraps Face ID / Touch ID / fingerprint / face unlock.

See auth-authz for the canonical OAuth/OIDC reference.

15. Roadmap signal

The Meta + Microsoft + Expo + community public roadmap for 2025-2026:

  • Bridgeless mode default (RN 0.76, October 2024). Done.
  • Static Hermes. Optionally typed JS subset that compiles ahead-of-time to faster machine code via Static Hermes. Experimental in 2024; targets 2-5× perf on hot paths.
  • Hermes for Web. Embed Hermes in browsers/Node for unified runtime; experimental.
  • Server Components in RN. React Server Components rendered server-side, streamed to RN. Expo demonstrated POCs at React Conf 2024; production rollout 2025-26.
  • Fabric for tvOS, visionOS. Microsoft and the community maintain React Native macOS, Windows, tvOS, visionOS variants.
  • Bun, Deno bundlers. Metro alternatives being explored; experimental.

15b. New Architecture migration in practice

The migration is gated by library compatibility. The React Native Directory (reactnative.directory) tracks per-library New Architecture support; as of late 2024, the top 100 community libraries are nearly all migrated, with a long tail of small libraries still on the legacy bridge.

Steps to enable in an existing app:

  1. Upgrade to RN 0.74+ (preferably 0.76 for Bridgeless default).
  2. Audit dependencies via npx @react-native-community/cli upgrade and the New Architecture compatibility checker.
  3. Flip the flag:
    • Android: newArchEnabled=true in android/gradle.properties.
    • iOS: RCT_NEW_ARCH_ENABLED=1 in Podfile environment + cd ios && pod install.
  4. Rebuild from clean (cd ios && pod deintegrate && pod install; cd android && ./gradlew clean).
  5. Test thoroughly — UI rendering paths change; some animations may need adjustment.

Symptoms of incomplete migration: red boxes referencing missing TurboModule registrations; views rendering blank because Fabric can’t find the legacy component spec. Fix: install a New Architecture-compatible version of the offending library, or write a Codegen spec to bridge a legacy module.

Expo SDK 51 (April 2024) shipped the New Architecture as opt-in; SDK 52 (October 2024) made it the default for new apps. EAS Build handles the build flags automatically when newArchEnabled: true is set in app.json.

15c. Reanimated worklets in depth

Reanimated 3’s worklet model is the technical anchor of the framework’s performance story. A worklet is a JavaScript function annotated with the 'worklet' directive at the top of its body; the Reanimated Babel plugin extracts the closure into a separate JS context that runs on the UI thread. Cross-thread state sharing uses useSharedValue, which allocates a SharedValue<T> box readable from both contexts.

const offset = useSharedValue(0);
 
const animatedStyle = useAnimatedStyle(() => {
  'worklet';
  return { transform: [{ translateX: offset.value }] };
});
 
const gesture = Gesture.Pan()
  .onUpdate((e) => {
    'worklet';
    offset.value = e.translationX;
  })
  .onEnd(() => {
    'worklet';
    offset.value = withSpring(0);
  });

The pan gesture fires on the UI thread, mutates the shared value on the UI thread, triggers useAnimatedStyle re-evaluation on the UI thread, applies the style to the view on the UI thread — JavaScript thread is never involved. 120 FPS gestures with no jank.

Worklet restrictions: cannot capture non-serialisable values; cannot call JS-thread functions (use runOnJS(fn) for explicit cross-thread invocation); cannot use most npm modules (must be pure JS). The Babel plugin enforces these at compile time.

15d. EAS Update operational model

EAS Update is a content-delivery network for JavaScript bundles. Each eas update invocation:

  1. Bundles the JS via Metro (or copies a prebuilt bundle).
  2. Uploads to EAS’s CDN with a unique update ID.
  3. Associates the update with a branch (e.g., production, staging).
  4. Marks it active for that branch’s matching channel (configured per build).

Apps fetch the latest update for their channel on startup (and optionally on background sync). The fetch is asynchronous; the app shows the previous bundle while downloading. Update is applied on the next app launch.

Atomic: the runtime never partially-applies an update. If download is interrupted, the old bundle remains active. Rollback by publishing an “empty” update (eas update --branch production --message "rollback" --republish <previous-update-id>) or by reverting source and re-publishing.

runtimeVersion (in app.json) gates compatibility. Increment the runtime version whenever you change native code; old apps stop receiving incompatible JS updates. Without this, an update that calls a new native module crashes existing installs.

Apple App Review policy (as of 2024-26): OTA updates may not “introduce features substantially different from what the App Store Review Approved.” Bug fixes, copy changes, UI tweaks, A/B tests — fine. Entirely new features or new revenue models — must re-submit.

15e. Code signing and credentials lifecycle

iOS: EAS holds the Distribution Certificate (.cer + .p12), Provisioning Profile (.mobileprovision), and App Store Connect API Key (.p8 + Key ID + Issuer ID). Rotate keys via eas credentials --platform ios; older builds remain valid until their provisioning profile expires (1 year typically).

Android: EAS holds the upload keystore (.jks). Play App Signing (required for AAB submissions) holds the actual app signing key on Google’s side; EAS only signs with the upload key. Lose the upload keystore → contact Play Support for upload key reset (one-time per app). Lose the app signing key (legacy apps before Play App Signing) → cannot update the app.

16. Common pitfalls

  • Mixing old and new architecture libraries. A library that hasn’t been ported to the New Architecture (Fabric/TurboModules) silently falls back to a bridge interop layer with perf cost; some libraries crash. Check react-native-config-info or the library’s CHANGELOG.
  • useEffect dependency arrays for navigation. Stale closures over navigation params are a common bug; use useFocusEffect and useCallback properly.
  • JS thread blocks. Heavy synchronous JS work (large JSON parse, big map operations) blocks the UI on legacy bridge; with JSI it still blocks JS-driven UI updates. Move heavy work to worklets or native.
  • Image memory. RN’s default Image component caches eagerly; lists of 100s of high-res images OOM on mid-range Android. Use expo-image (Sharp under the hood) or react-native-fast-image (deprecated, no New Architecture support — use expo-image).
  • EAS build credential drift. Local + EAS credentials can desync; eas credentials to inspect/sync.
  • OTA update breaking native compatibility. Shipping a JS bundle that calls a native module not present in the installed app version crashes. Use runtimeVersion to gate updates; SDK 52+ enforces it.
  • Hermes/JSC differences. Some libraries assume JSC’s behaviour (older regex, Intl) and break on Hermes. The Hermes compatibility doc lists known gaps.

17. When to choose RN vs alternatives

RN’s sweet spot: teams with React/web experience, projects targeting iOS + Android (+ optionally web via Expo Router), apps where 80% of the surface is standard CRUD/form/feed UI + the remaining 20% has clear native module paths. Best when the team values the React mental model and the npm ecosystem.

Avoid RN when: graphics-heavy gaming (use Unity/Unreal/Flame), apps that are 50%+ custom rendering (Flutter handles consistency better), pure-Android or pure-iOS apps where native development is faster.

Compared to alternatives: see flutter-and-dart-deep and capacitor-pwa-and-cross-platform-web.

18. Observability in production

Production RN apps instrument across three layers:

  • JS errors. Sentry (@sentry/react-native), Bugsnag, Datadog RUM. Source-map upload during build (Sentry CLI: sentry-cli sourcemaps upload) enables minified-stack-trace resolution.
  • Native crashes. Same SDKs catch native crashes (ObjC exceptions, Java/Kotlin uncaught throwables) and symbolicate via dSYM (iOS) and mapping.txt (Android R8) uploads.
  • Performance. Sentry Performance, Datadog RUM, Embrace, Firebase Performance. Track route navigation timings, slow JS frames, image loads.

Hermes provides JS sampling profiles consumable by the Chrome DevTools Performance panel; capture via chrome://inspect/#devices while the debugger is attached.

Network observability via Flipper or via OkHttp/URLSession-level interceptors (instrumented by Datadog / Sentry). Track API latency, error rates, payload sizes per endpoint.

19. On-device ML in React Native

  • react-native-executorch (Software Mansion, 2024). PyTorch ExecuTorch runtime wrapper. Run quantised LLMs (Llama 3.2 1B-3B), Whisper, classification models on iOS + Android.
  • react-native-fast-tflite. TensorFlow Lite (now LiteRT) wrapper with GPU delegate support.
  • onnxruntime-react-native. Microsoft ONNX Runtime; cross-platform model execution.
  • VisionCamera + Frame Processors. Mark Rousavy’s camera library; frame processors expose per-frame pixel buffers to JS for ML inference (e.g., real-time pose estimation, OCR).

The 2024-26 wave of on-device LLM apps (Llama-on-phone, Gemma-on-phone) is increasingly RN-based because the model integration is one JSI module away from the existing app. See inference-optimization for the cross-platform mobile ML landscape.

Further reading

  • React Native Documentation (reactnative.dev) — architecture chapters are now canonical.
  • Expo Documentation (docs.expo.dev) — practical recipes.
  • Fabric and TurboModules (RN blog posts from 2020-2024).
  • Marc Rousavy, VisionCamera and MMKV technical blog posts.
  • Krzysztof Magiera (Reanimated/Software Mansion) — RN Conf talks on the worklet model.
  • The State of React Native 2024 survey (community, ~2K respondents).
  • React Native Performance (William Candillon, YouTube).
  • React Native Radio podcast.

Adjacent