Key Architectural Patterns Used in React Native: From Legacy Bridge to New Architecture
React Native implements a layered architecture built on the JavaScript Interface (JSI), TurboModules for native modules, Fabric for UI rendering, and Bridgeless mode to eliminate the legacy serialization bottleneck.
The facebook/react-native repository powers cross-platform mobile applications through a sophisticated runtime that has evolved from the original bridge-based model to the modern New Architecture. Understanding the key architectural patterns used in React Native is essential for optimizing performance, building native modules, and migrating legacy codebases.
The Evolution of React Native Architecture
React Native’s runtime has transitioned from a message-queue-based bridge to a synchronous, type-safe system. The original Legacy Bridge relied on asynchronous JSON serialization between JavaScript and native threads, while the modern stack uses JSI to enable direct memory access and synchronous execution.
Core Architectural Patterns in React Native
Legacy Bridge Pattern
The Legacy Bridge serializes calls between JavaScript and native code (Objective-C/Java) via a message queue. This pattern creates latency when transferring large data payloads because all communication must be marshalled into JSON and dispatched asynchronously. The bridge implementation lives in packages/react-native/React/Base/RCTBridge.h.
JavaScript Interface (JSI)
JSI is a low-level, fast, synchronous C++ API that lets native code call into the JS runtime (Hermes, V8, JavaScriptCore) without bridge overhead. Defined in packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h, JSI enables direct memory sharing and eliminates serialization bottlenecks by allowing native code to hold references to JavaScript objects.
Hermes JavaScript Engine
Hermes is a lightweight JS engine optimized for React Native that integrates directly with JSI. The integration point is packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.h, which creates the runtime instance used by JSIExecutor to enable bytecode precompilation and reduced memory footprint.
TurboModules
TurboModules are C++-based native modules that expose a typed interface to JavaScript through JSI, eliminating the bridge for module calls. The iOS implementation in packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm handles module registration, lazy loading, and type-safe method invocation.
Fabric Renderer
Fabric is the next-generation UI renderer that replaces the original UIManager. It uses a shadow tree + component descriptor model and talks to JavaScript through JSI, providing fine-grained layout and mutation updates. The component registry is defined in packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp.
Bridgeless Architecture
The Bridgeless Architecture removes the legacy bridge entirely; the app boots directly into a JSI-powered runtime, enabling TurboModules and Fabric out-of-the-box. This mode is controlled by the enableBridgelessArchitecture flag in packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js.
How the Architectural Patterns Work Together
Application Startup
With Bridgeless enabled, the native side creates a JSI runtime (Hermes by default) and registers the TurboModule provider and Fabric component registry. The entry point that ties everything together lives in packages/react-native/ReactCommon/react/runtime/JSIExecutor.cpp.
JavaScript to Native Communication
Calls flow through JSI directly without serialization. UI components are rendered by Fabric, with layout computed in C++ and the result pushed to the native view hierarchy. Native modules are instantiated as TurboModules, accessed via TurboModuleRegistry.getEnforcing(...).
Native to JavaScript Callbacks
Native code can call back into JS instantly through JSI objects (e.g., jsi::Function). No message-queue marshalling is required, enabling synchronous execution where necessary.
Feature Flag Coordination
Runtime behaviour is controlled by ReactNativeFeatureFlags. Turning on enableBridgelessArchitecture automatically enables TurboModules and Fabric, ensuring the cohesive New Architecture stack is active.
Implementing React Native Architectural Patterns
Consuming a TurboModule in JavaScript
// src/MyTurboModule.js
import {TurboModuleRegistry} from 'react-native';
import type {TurboModule} from 'react-native/Libraries/TurboModule/TurboModule';
// Define the TypeScript spec (generated by codegen in a real project)
export interface Spec extends TurboModule {
getValue: (x: number) => Promise<string>;
voidFunc: () => void;
}
// Retrieve the native module
const MyTurbo = TurboModuleRegistry.getEnforcing<Spec>('MyTurboModule');
// Example usage
export async function fetchValue() {
const res = await MyTurbo.getValue(42);
console.log('TurboModule returned:', res);
}
MyTurbo.voidFunc();
Source: The example lives in the repository at packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js.
Rendering with Fabric
// src/MyFabricComponent.js
import * as React from 'react';
import {View, Text, StyleSheet} from 'react-native';
// When the new architecture is enabled this component is rendered by Fabric
export default function MyFabricComponent() {
return (
<View style={styles.box}>
<Text>Rendered with Fabric 🎨</Text>
</View>
);
}
const styles = StyleSheet.create({
box: {
padding: 16,
backgroundColor: '#e0f7fa',
},
});
Source: The shim that bridges to the native Fabric renderer is packages/react-native/Libraries/Renderer/shims/ReactFabric.js.
Creating a JSI Module in C++
// MyJSIModule.cpp
#include <jsi/jsi.h>
using namespace facebook::jsi;
void installMyJSIModule(Runtime& runtime) {
// Expose a simple `add(a, b)` function to JS
runtime.global().setProperty(
runtime,
"add",
Function::createFromHostFunction(
runtime,
PropNameID::forAscii(runtime, "add"),
2,
[](Runtime& rt,
const Value& thisValue,
const Value* args,
size_t count) -> Value {
double a = args[0].asNumber();
double b = args[1].asNumber();
return Value(a + b);
}));
}
In the app’s entry point (JSIExecutor.cpp) the module is installed:
// JSIExecutor.cpp (excerpt)
void JSIExecutor::installBindings(Runtime& runtime) {
// … existing bindings …
installMyJSIModule(runtime); // <-- custom module
}
Source: packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp and example at packages/rn-tester/js/examples/JSI/NativeJsiModuleExample.js.
Enabling the New Architecture in iOS
# ios/Podfile
require_relative '../node_modules/react-native/scripts/react_native_pods'
target 'MyApp' do
# Enable the New Architecture (TurboModules + Fabric + Bridgeless)
use_react_native!(
:path => config[:reactNativePath],
:new_arch_enabled => true # <-- key flag
)
end
When new_arch_enabled is true the helper NewArchitectureHelper injects the required compiler flags and pods.
Source: packages/react-native/scripts/cocoapods/new_architecture.rb.
Key Source Files for React Native Architecture
| Area | Important File | Purpose |
|---|---|---|
| Runtime entry | packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp |
Creates the JSI runtime (Hermes/JSCore) and installs bindings. |
| TurboModules | packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm |
Registers and resolves TurboModules on iOS. |
| Fabric renderer | packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp |
Holds the component descriptor registry used by Fabric. |
| Feature flags | packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js |
Central toggles (enableBridgelessArchitecture, enableTurboModules, enableFabricRenderer). |
| New-architecture build helper | packages/react-native/scripts/cocoapods/new_architecture.rb |
Adjusts pod installation and compiler flags for the New Architecture. |
| JS shim for Fabric | packages/react-native/Libraries/Renderer/shims/ReactFabric.js |
Public JS API that forwards calls to the native Fabric renderer. |
| Example TurboModule usage | packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js |
Demonstrates how a JS app consumes a TurboModule. |
| Example JSI native module | packages/rn-tester/js/examples/JSI/NativeJsiModuleExample.js |
Shows how a C++ JSI module is exposed to JavaScript. |
Summary
- JSI (JavaScript Interface) provides the synchronous, low-level C++ foundation that replaces the asynchronous Legacy Bridge.
- TurboModules expose native functionality to JavaScript through JSI with type safety and lazy loading, eliminating bridge serialization.
- Fabric renders UI components using a C++ shadow tree and component descriptors, communicating synchronously with JavaScript via JSI.
- Bridgeless Architecture removes the legacy bridge entirely, booting directly into a JSI-powered runtime with TurboModules and Fabric enabled by default.
- Hermes serves as the optimized JavaScript engine that integrates tightly with JSI to enable these synchronous, high-performance operations.
Frequently Asked Questions
What is the difference between the Legacy Bridge and JSI in React Native?
The Legacy Bridge serializes all communication between JavaScript and native code into JSON messages that are processed asynchronously through a message queue, creating inherent latency. JSI (JavaScript Interface) is a synchronous C++ API that allows native code to hold direct references to JavaScript objects and invoke them immediately without serialization, effectively eliminating the bridge bottleneck.
How do TurboModules improve performance compared to legacy native modules?
TurboModules leverage JSI to expose native methods directly to JavaScript without asynchronous bridge marshalling, allowing for synchronous execution where required. They also implement lazy loading—modules are only instantiated when first accessed through TurboModuleRegistry.getEnforcing()—and use type-safe interfaces generated by the New Architecture's codegen, reducing both memory usage and runtime errors.
What is Fabric in React Native's New Architecture?
Fabric is the next-generation UI renderer that replaces the original UIManager, utilizing a C++ shadow tree and component descriptor registry to calculate layouts and mutations. It communicates with JavaScript synchronously through JSI rather than the asynchronous bridge, enabling fine-grained priority scheduling for UI updates and significantly reducing touch latency and rendering jank.
How do I enable the New Architecture in my React Native project?
Enable the New Architecture by setting new_arch_enabled: true in your ios/Podfile (for iOS) or newArchEnabled=true in android/gradle.properties (for Android). This activates the NewArchitectureHelper script, which configures the build system to use TurboModules, Fabric, and Bridgeless mode by injecting the necessary compiler flags and dependencies, effectively replacing the legacy bridge with the JSI-based runtime.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →