React Native's New Architecture replaces the old communication layer between JavaScript and native code. Its main pieces are JSI, Fabric, and TurboModules.
The goal is to replace the asynchronous, JSON-based Bridge that constrained communication between JavaScript and native code.
1. The Three Pillars
The New Architecture is built on three main components:
- JSIJavaScript Interface
- FabricNew Rendering System
- TurboModulesNew Native Modules
JSI (JavaScript Interface)
The JSI is a lightweight, general-purpose layer that allows the JavaScript engine to call methods on the native side directly, and vice versa. No more JSON serialization!
What This Means:
Before JSI, when your JavaScript code wanted to call a native function (like accessing the camera), the request had to be:
- Serialized to JSON
- Sent across the Bridge (asynchronous)
- Deserialized on the native side
- Executed
- Response serialized back to JSON
- Sent back across the Bridge
- Deserialized in JavaScript
With JSI, JavaScript code can directly invoke native functions and hold references to native objects in memory. It's synchronous, fast, and type-safe.
// Old Bridge Way (Asynchronous)
NativeModules.CameraManager.takePicture().then((photo) => {
console.log(photo);
});
// New JSI Way (Synchronous)
const photo = global.CameraManager.takePicture();
console.log(photo); // Immediately available
Performance Impact:
- Old: 50-100ms for simple native calls (serialization overhead)
- New: <1ms for simple native calls (direct function invocation)
Direct communication also makes these patterns practical:
- Real-time gesture handling (60fps smooth animations)
- Synchronous layout calculations
- Direct memory sharing between JS and native (e.g., for image processing)
Fabric
Fabric is the new rendering system that brings many benefits, including synchronous layout and improved performance for complex UIs.
The Problem with the Old Renderer:
The old React Native renderer had a fundamental issue: asynchronous layout.
When you rendered a component:
- React calculates the component tree in JavaScript
- Sends layout instructions over the Bridge
- Native side calculates layout asynchronously
- Sends dimensions back over the Bridge
- JavaScript updates state based on dimensions
- Repeat (causing jank and layout thrashing)
Fabric's Solution:
Fabric makes layout synchronous and runs entirely in C++, allowing:
- Priority-based rendering: High-priority updates (e.g., user input) render immediately
- Concurrent rendering: Background updates don't block UI
- Interruptible rendering: Cancel in-progress renders when new data arrives
// Example: Synchronous Layout with Fabric
function MeasureExample() {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const ref = useRef(null);
useEffect(() => {
// With Fabric, this is synchronous!
const { width, height } = ref.current.getBoundingClientRect();
setDimensions({ width, height });
}, []);
return <View ref={ref}>Content</View>;
}
Real-World Impact:
Testing by the React Native team showed:
- Complex list rendering: 40% faster
- Layout recalculations: 60% faster
- Animation frame drops: 70% reduction
TurboModules
TurboModules allow for lazy loading of native modules, meaning your app only loads what it needs when it needs it, drastically improving startup time.
The Old Problem:
In the old architecture, all native modules were loaded at startup, even if your app never used them.
If your app had 50 native modules, all 50 were:
- Initialized at startup
- Kept in memory for the entire session
- Slowing down your app launch
TurboModules Solution:
Modules are lazy-loaded only when first used, and they use JSI for direct invocation.
// Old Way: All modules loaded upfront
// NativeModules.Geolocation (loaded at startup, even if never used)
// New Way: TurboModule loaded on-demand
import { TurboModuleRegistry } from "react-native";
// Only loaded when first called
const Geolocation = TurboModuleRegistry.get("Geolocation");
// First call loads the module
const position = Geolocation.getCurrentPosition();
Startup Time Improvements:
Real-world data from Meta's internal apps:
- Facebook App50% faster startup
- Instagram App40% faster startup
- Messenger App45% faster startup
2. Performance Comparison
- Bridge (Old)Async + Serialization + Middleman
- JSI (New)Sync + Direct Access
- Delta~30% faster UI interactions
Let's look at concrete benchmarks from real-world scenarios:
Benchmark 1: FlatList Scrolling
Test: Render 1,000 items in a FlatList and measure scroll performance.
Old Architecture:
- Initial render: 2,800ms
- Scroll to item 500: 4-6 dropped frames
- Memory usage: 180MB
New Architecture:
- Initial render: 1,600ms (43% faster)
- Scroll to item 500: 0-1 dropped frames (95% improvement)
- Memory usage: 120MB (33% reduction)
Benchmark 2: Complex Animations
Test: Run 10 simultaneous animations with gesture interactions.
Old Architecture:
- Average FPS: 48fps (dropped 12 frames per second)
- Touch response delay: 80-120ms
- CPU usage: 65%
New Architecture:
- Average FPS: 59fps (nearly perfect 60fps)
- Touch response delay: 15-25ms (75% improvement)
- CPU usage: 42% (35% reduction)
Benchmark 3: App Startup Time
Test: Cold start of production app with 30+ screens.
- Old Architecture3.2s to interactive
- New Architecture1.8s to interactive
- Improvement44% faster
3. Migration Strategy
Should You Migrate?
The New Architecture is now the default in React Native 0.76+, but migrating existing complex apps requires careful testing of third-party libraries.
Migration Checklist:
-
Audit Your Dependencies
Check if your third-party libraries support the New Architecture:
npx react-native-community/cli@latest infoLook for warnings about unsupported modules.
-
Enable New Architecture Gradually
You can enable it per-platform:
// android/gradle.properties newArchEnabled=true // ios/Podfile use_frameworks! :linkage => :static $RNNewArchEnabled = true -
Test Critical Flows
Focus on:
- Payment flows (native modules)
- Camera/media capture
- Push notifications
- Deep linking
- Background tasks
-
Monitor Performance
Use React DevTools Profiler and native profilers:
import { startProfiler, stopProfiler, } from "react-native/Libraries/Performance"; startProfiler("AppStartup"); // ... your app code stopProfiler("AppStartup");
Common Migration Issues
Issue 1: Native Module Incompatibility
Some older native modules aren't compatible with TurboModules.
Solution:
- Check for updated versions
- Fork and update the module yourself
- Replace with compatible alternatives
Issue 2: Direct Manipulation APIs
Old UIManager.measure() calls need updates:
// Old Way
UIManager.measure(node, (x, y, width, height) => {
console.log({ x, y, width, height });
});
// New Way
ref.current.measure((x, y, width, height) => {
console.log({ x, y, width, height });
});
Issue 3: AsyncStorage
Replace deprecated AsyncStorage with community package:
npm install @react-native-async-storage/async-storage
When to Migrate
Migrate Now If:
- Starting a new project (it's the default!)
- Your app is performance-critical (games, media apps)
- You're already on React Native 0.70+
- Your dependencies are compatible
Wait If:
- You have many legacy native modules
- You're on an older RN version (<0.68)
- Your app is stable and performance is acceptable
- You lack resources for thorough testing
4. The Future: What's Next?
The New Architecture supports capabilities that were difficult with the Bridge:
1. Shared Element Transitions
With synchronous layout and direct JSI access, native-quality shared element transitions are now possible:
import { SharedElement } from "react-native-shared-element";
function ListScreen() {
return (
<SharedElement id="photo-123">
<Image source={photo} />
</SharedElement>
);
}
function DetailScreen() {
return (
<SharedElement id="photo-123">
<Image source={photo} />
</SharedElement>
);
}
2. Real-time Collaboration
Synchronous updates enable real-time collaborative features like Google Docs:
function CollaborativeEditor() {
useEffect(() => {
// Synchronous cursor updates via JSI
const unsubscribe = collaboration.onCursorMove((cursor) => {
updateCursorPosition(cursor); // No Bridge delay!
});
return unsubscribe;
}, []);
}
3. Advanced Graphics
Direct memory access enables high-performance graphics:
import { Canvas } from "@shopify/react-native-skia";
function GameCanvas() {
// 60fps canvas rendering with JSI
return (
<Canvas style={{ flex: 1 }}>
{/* Rendered in native Skia engine */}
<Rect x={0} y={0} width={100} height={100} color="red" />
</Canvas>
);
}
5. Reported production results
- Checkout Flow - 40% faster
- Crash Rates - 30% reduction
- App Ratings - 25% improvement
- Message Scrolling - 59fps vs 45fps
- Channel Switching - 200ms vs 450ms
- Animation - Better performance
- Startup Time - 50% faster
- Memory Usage - 35% reduction
- Call Quality - Improved latency
6. Should you migrate?
Resources and learning path
- Official New Architecture Guidereactnative.dev
- React Native 0.76 Release Blogreactnative.dev
- JSI Deep Dive by Software Mansionblog.swmansion.com
- Fabric Renderer Documentationreactnative.dev
- TurboModules Guidereactnative.dev
Learning Roadmap:
- Week 1: Understand JSI and Bridge differences
- Week 2: Study Fabric renderer concepts
- Week 3: Learn TurboModules implementation
- Week 4: Migrate a small test app
- Week 5+: Migrate production app gradually
For a new React Native project, the New Architecture is the default. Existing apps need a dependency audit, targeted performance measurements, and a gradual migration plan. The useful question is not whether the architecture is newer, but whether its native-module model and renderer solve problems your app can measure.
