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:

  1. Serialized to JSON
  2. Sent across the Bridge (asynchronous)
  3. Deserialized on the native side
  4. Executed
  5. Response serialized back to JSON
  6. Sent back across the Bridge
  7. 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:

  1. React calculates the component tree in JavaScript
  2. Sends layout instructions over the Bridge
  3. Native side calculates layout asynchronously
  4. Sends dimensions back over the Bridge
  5. JavaScript updates state based on dimensions
  6. 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:

  1. Initialized at startup
  2. Kept in memory for the entire session
  3. 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:

  1. Audit Your Dependencies

    Check if your third-party libraries support the New Architecture:

    npx react-native-community/cli@latest info
    

    Look for warnings about unsupported modules.

  2. Enable New Architecture Gradually

    You can enable it per-platform:

    // android/gradle.properties
    newArchEnabled=true
    
    // ios/Podfile
    use_frameworks! :linkage => :static
    $RNNewArchEnabled = true
    
  3. Test Critical Flows

    Focus on:

    • Payment flows (native modules)
    • Camera/media capture
    • Push notifications
    • Deep linking
    • Background tasks
  4. 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

Shopify
  • Checkout Flow - 40% faster
  • Crash Rates - 30% reduction
  • App Ratings - 25% improvement
Discord
  • Message Scrolling - 59fps vs 45fps
  • Channel Switching - 200ms vs 450ms
  • Animation - Better performance
Microsoft Teams
  • Startup Time - 50% faster
  • Memory Usage - 35% reduction
  • Call Quality - Improved latency

6. Should you migrate?


Resources and learning path

Learning Roadmap:

  1. Week 1: Understand JSI and Bridge differences
  2. Week 2: Study Fabric renderer concepts
  3. Week 3: Learn TurboModules implementation
  4. Week 4: Migrate a small test app
  5. 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.