React Native Architecture: Old vs New
A side-by-side overview of the legacy React Native architecture and the New Architecture (Fabric + TurboModules + JSI + Hermes + Codegen), with a side-by-side comparison table, a release timeline, and SVG diagrams.
Architecture comparison
Overview
The legacy React Native architecture relied on an asynchronous JSON bridge to communicate between the JavaScript thread and the native UI thread. While simple and broadly compatible, the bridge became a well-known performance and correctness bottleneck as apps grew.
Threads
JavaScript thread
- Executes React component logic, hooks, and state updates
- Runs the React reconciler to compute the virtual element tree
- Sends diffs to native via the bridge on each render
Native / UI thread
- Receives view operations from the bridge and applies them to the native view hierarchy
- Handles user input, gestures, and platform-level rendering
- Dispatches responses (events, callbacks) back through the bridge
Shadow thread
- Computes Yoga layout for the shadow tree off the main threads
- Produces layout metadata the UI thread applies to native views
How the Bridge Worked
How the Bridge Worked. Every call between JavaScript and native was serialized as JSON, queued, and processed asynchronously on the other side. JSON serialization, queueing, and deserialization dominated cross-thread latency and prevented synchronous reads of native values from JS.
Problems
Asynchronous, JSON-serialized bridge
All JS↔native traffic was serialized to JSON and processed on a queue, adding latency and preventing synchronous access to native values.
Duplicated work in three threads
JS, Shadow, and Native threads each maintained parallel state of the tree, increasing memory pressure and the chance of inconsistencies.
Cost of repeated serialization
Frequent updates paid the full JSON (de)serialization cost on every render, hurting scroll and animation performance.
No synchronous native calls
The bridge was strictly async, so measuring layout, reading persistent values, or invoking imperative methods required extra round-trips.
Slower startup time
Module initialization and bridge warm-up delayed time-to-interactive, especially on Android.
Rendering Flow
- React Code
- JSC
- Bridge (JSON Serialization)
- Native Modules
- UIManager
- Yoga
- Native Views
Diagram
Key terms in this diagram
- React Code
- Your React components, hooks, and state. Runs JavaScript that drives the UI.
- JavaScriptCore (JSC)
- Apple's JavaScript engine that executed React Native code on both iOS and Android in the legacy architecture.
- Bridge
- The asynchronous boundary between the JS thread and the native threads. Every call was serialized to JSON, queued, and decoded on the other side.
- Native Modules
- Platform-specific code (camera, location, storage, sensors) that the bridge exposed to JavaScript.
- UIManager
- The native module that owned the view hierarchy: it created, updated, and destroyed native views in response to bridge messages.
- Yoga
- Facebook's cross-platform layout engine. Ran on a separate shadow thread and computed flexbox-style positions and sizes for every node in the view tree.
- Native Views
- The actual platform UI objects (UIView on iOS, android.view.View on Android) that the OS rendered to the screen.
Overview
The New Architecture (Fabric + TurboModules + JSI + Codegen, with Hermes) replaces the bridge with synchronous, direct bindings to a C++ layer. Work is shared between JS, the JSI/C++ runtime, and the new Fabric renderer, enabling concurrent React, lazy module loading, and type-safe native interfaces.
JavaScript Runtime
JavaScript runtime (Hermes / V8)
- Runs React and user JavaScript with optimized ahead-of-time compilation
- Communicates with native through the JSI using direct C++ bindings (no JSON serialization)
Key Components
JSI (JavaScript Interface)
A lightweight C++ API that lets JavaScript hold direct references to C++ objects and invoke them synchronously, replacing the asynchronous JSON bridge.
- Direct, synchronous JS↔C++ calls with no serialization overhead
- Enables native modules and the renderer to share memory with JS
TurboModules
The next-generation native module system, lazily loaded on demand and described by statically-typed specs generated by Codegen.
- Lazy module loading keeps cold-start fast in large apps
- Statically typed interfaces catch mismatches at build time
Fabric
A new concurrent renderer that produces a shadow tree and mounts native views with improved prioritization and synchronous layout where possible.
- Supports React 18 concurrent features such as automatic batching and transitions
- Renders with C++ shadow nodes shared between JS, layout, and native
Hermes
An open-source JavaScript engine optimized for React Native, with ahead-of-time bytecode compilation and a small footprint.
- Faster startup and reduced memory usage compared to JSC
- Predictable performance for mid-range devices
Codegen
Generates statically-typed native interface bindings from a JavaScript spec at build time, replacing the dynamic bridge contract.
- Compile-time type safety across the JS/native boundary
- Removes runtime reflection and reduces surface area for bugs
Rendering Flow
- JS Code
- Hermes/V8
- JSI
- TurboModules
- Fabric
- React Reconciler
- Shadow Nodes/Shadow Tree
- Yoga
- Mounting Layer
- Native Views
Diagram
Key terms in this diagram
- JS Code
- Your React components, hooks, and state. Runs JavaScript that drives the UI.
- Hermes / V8
- Optimized JavaScript engines (Hermes is the default; V8 is an option) with ahead-of-time compilation, faster startup, and a smaller memory footprint than JSC.
- JSI (JavaScript Interface)
- A thin C++ API that lets JavaScript hold direct references to C++ objects and invoke them synchronously. Replaces the JSON bridge.
- TurboModules
- The next-generation native module system. Each module is described by a statically-typed spec (generated by Codegen) and is loaded lazily on first use, instead of being initialized eagerly at startup.
- Fabric
- The new concurrent renderer. Supports React 18 concurrent features (automatic batching, transitions, Suspense) and produces shadow trees with prioritized updates.
- React Reconciler
- The part of React that diffs the previous and next virtual trees and emits the minimal set of changes for the renderer to apply.
- Shadow Nodes / Shadow Tree
- A C++ representation of the view tree that is shared between JavaScript, layout (Yoga), and the mounting layer. One tree replaces the three parallel trees the old architecture kept in sync.
- Yoga
- Facebook's cross-platform layout engine. Computes flexbox-style positions and sizes for the shadow tree, so the same layout logic runs on every platform.
- Mounting Layer
- Translates shadow node updates into actual native view mutations: create, insert, update, remove. It is the single point where shadow state becomes platform UI.
- Native Views
- The actual platform UI objects (UIView on iOS, android.view.View on Android) that the OS renders to the screen.
Comparison
| Aspect | Old Architecture | New Architecture |
|---|---|---|
| JavaScript Engine | JavaScriptCore (JSC) on iOS and Android, with optional Hermes opt-in. | Hermes by default, with optional V8; AOT compilation and smaller footprint. |
| Communication Layer | Asynchronous, JSON-serializing bridge between JS and native threads. | JSI: direct, synchronous C++ bindings between JS and the native runtime. |
| Module System | Native Modules: all modules initialized eagerly at app start. | TurboModules: lazily loaded on demand, described by static specs. |
| Rendering System | Legacy renderer with paper UIManager and async bridge updates. | Fabric renderer with concurrent React, shadow tree, and prioritized updates. |
| Serialization | Every cross-thread call JSON-encodes data, queuing and decoding on the other side. | No JSON serialization; JS holds direct C++ object references via JSI. |
| Synchronous Calls | Not supported by the bridge; all cross-thread work is async. | Supported via JSI; sync layout reads and imperative calls are first-class. |
| Startup Time | Slower: all modules and the bridge warm up before first paint. | Faster: lazy TurboModules and Hermes AOT reduce time-to-interactive. |
| Memory Usage | Three parallel trees (JS, Shadow, Native) plus queued bridge messages. | Shared C++ shadow tree and lazy module loading lower baseline memory. |
| Module Loading | Eager: Native Modules are created and registered at startup. | Lazy: TurboModules initialize on first call, guarded by Codegen specs. |
| React Concurrent Support | Limited; the async bridge breaks assumptions of concurrent rendering. | Full: Fabric integrates with React 18 concurrent features and Suspense. |
| Performance | Bridge bottlenecks under heavy updates; scroll and animation suffer on mid-range devices. | Lower latency per update; smoother interactions thanks to JSI and Fabric prioritization. |
| Type Safety | Dynamic contract: mistakes surface at runtime as bridge errors. | Static contract: Codegen produces typed bindings validated at build time. |
Release Timeline
- 0.68Experimental opt-in
First release where the New Architecture could be enabled behind a flag for testing.
- 0.76Default
New Architecture is enabled by default for new projects while still allowing opt-out.
- 0.82Only architecture
Old Architecture is removed; the New Architecture is the only supported runtime.