Understanding Hermes, Fabric, and the New Architecture in React Native



This content originally appeared on DEV Community and was authored by Nader Alfakesh

🚀 Understanding Hermes, Fabric, and the New Architecture in React Native

If you’ve been building React Native apps for a while, chances are you’ve heard terms like Hermes, TurboModules, and Fabric floating around. When I recently upgraded from an older React Native project to v0.80.2, I realized these weren’t just buzzwords—they’re a fundamental shift in how React Native works under the hood.

This guide will demystify these technologies and show you why they matter for your next React Native project.

📋 Table of Contents

  • The Evolution of React Native
  • Hermes: The JavaScript Engine Built for Mobile
  • The New Architecture: Beyond the Bridge
  • TurboModules: Native Modules, Supercharged
  • Fabric: Modern UI for Modern React
  • Migration Guide
  • Performance Comparisons
  • Conclusion

🎯 The Evolution of React Native

Before diving into the new technologies, let’s understand the journey:

📅 Timeline
2015: React Native Launch → JavaScript Bridge Architecture
2017: Hermes Development Begins → Focus on Mobile Performance
2018: New Architecture Announced → JSI Introduction
2022: New Architecture Stable → Fabric & TurboModules
2024: Default in New Projects → Mature Ecosystem

🧠 Hermes: The JavaScript Engine Built for Mobile

React Native originally relied on JavaScriptCore (JSC), but Hermes was introduced as a mobile-first JS engine optimized specifically for React Native apps.

Key Benefits:

🚀 Faster Startup Time

// Traditional JSC Flow
Source Code  Parse  Compile  Execute

// Hermes Flow
Source Code  Precompile to Bytecode  Execute

💾 Lower Memory Usage

Perfect for low-end Android devices. Here’s a real-world comparison:

Memory Usage Comparison (50MB App):
JSC:    ~185MB RAM
Hermes: ~136MB RAM (-26%)

🔄 Smaller Bundle Size

Bundle Size Impact:
Before Hermes: 41MB APK
After Hermes:  29MB APK (-29%)

💡 Enabling Hermes in Your Project

Most new React Native projects now enable Hermes by default. Here’s how to check:

Android (android/app/build.gradle):

android {
    ...
    packagingOptions {
        pickFirst '**/libc++_shared.so'
        pickFirst '**/libjsc.so'
    }
}

// Hermes is enabled by this flag
hermesEnabled = true

iOS (ios/Podfile):

use_react_native!(
  :path => config[:reactNativePath],
  # Hermes is now enabled by default
  :hermes_enabled => true,
  :fabric_enabled => flags[:fabric_enabled],
)

⚡ The New Architecture: Beyond the Bridge

The classic React Native model relied on a Bridge for JS-to-Native communication:

Old Bridge Architecture:

┌─────────────┐     JSON      ┌──────────────┐
│ JavaScript  │ ←----------→  │    Native    │
│   Thread    │   Serialize   │   Thread     │
└─────────────┘               └──────────────┘
       ↓                              ↓
   [Async Queue]                [Processing]
       ↓                              ↓
   [Batching]                    [Response]

New JSI Architecture:

┌─────────────┐               ┌──────────────┐
│ JavaScript  │ ←----------→  │    Native    │
│   Thread    │  Direct C++   │   Thread     │
└─────────────┘   Interface   └──────────────┘
       ↓                              ↓
   [Immediate]                  [Immediate]

Performance Impact:

// Old Bridge (Async)
NativeModules.Camera.takePicture((result) => {
  // Wait for bridge...
  console.log(result); // ~16-32ms delay
});

// New JSI (Sync when needed)
const result = Camera.takePictureSync();
console.log(result); // <1ms delay

🛠 TurboModules: Native Modules, Supercharged

TurboModules revolutionize how we interact with native code:

Key Features:

  • Lazy Loading: Modules load only when needed
  • Type Safety: Auto-generated TypeScript bindings
  • Synchronous Calls: When performance matters
  • Direct JSI Access: No serialization overhead

Creating a TurboModule:

1. Define the Native Module Interface:

// specs/NativeDeviceInfo.ts
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
  getBatteryLevel(): number;
  getDeviceId(): string;
  isTablet(): boolean;
}

export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');

2. Native Implementation (iOS):

// RNDeviceInfo.mm
#import "RNDeviceInfo.h"

@implementation RNDeviceInfo

RCT_EXPORT_MODULE(DeviceInfo)

- (NSNumber *)getBatteryLevel {
  UIDevice *device = [UIDevice currentDevice];
  device.batteryMonitoringEnabled = YES;
  return @(device.batteryLevel);
}

- (NSString *)getDeviceId {
  return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
}

- (NSNumber *)isTablet {
  return @(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}

@end

3. Usage in JavaScript:

import DeviceInfo from './specs/NativeDeviceInfo';

// Direct, synchronous calls!
const batteryLevel = DeviceInfo.getBatteryLevel();
const deviceId = DeviceInfo.getDeviceId();
const isTablet = DeviceInfo.isTablet();

console.log(`Battery: ${batteryLevel * 100}%`);
console.log(`Device ID: ${deviceId}`);
console.log(`Is Tablet: ${isTablet}`);

🎨 Fabric: Modern UI for Modern React

Fabric is React Native’s new rendering system, built from the ground up to support modern React features:

Architecture Comparison:

Old Renderer:

React Components
      ↓
Shadow Thread (Layout)
      ↓
Bridge (JSON)
      ↓
Main Thread (UI)

Fabric Renderer:

React Components
      ↓
Fabric C++ Core
   ↙     ↘
iOS UI   Android UI
(Sync)    (Sync)

Key Improvements:

1. Concurrent Rendering Support

// Now works seamlessly with React 18 features
function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ExpensiveComponent />
    </Suspense>
  );
}

2. Priority-based Rendering

// High priority updates (user input)
<TextInput onChangeText={setText} />

// Low priority updates (background data)
<LargeList data={backgroundData} />

3. Better Animations

// Fabric enables smoother 60fps animations
const animatedValue = useSharedValue(0);

const animatedStyle = useAnimatedStyle(() => ({
  transform: [{
    translateX: withSpring(animatedValue.value * 100)
  }]
}));

📊 Performance Comparisons

Real-world Metrics:

┌─────────────────┬──────────┬──────────┬─────────┐
│ Metric          │ Old Arch │ New Arch │ Change  │
├─────────────────┼──────────┼──────────┼─────────┤
│ App Start Time  │ 3.2s     │ 1.8s     │ -44%    │
│ List Scroll FPS │ 47 fps   │ 59 fps   │ +25%    │
│ Memory Usage    │ 185 MB   │ 136 MB   │ -26%    │
│ Bundle Size     │ 41 MB    │ 29 MB    │ -29%    │
└─────────────────┴──────────┴──────────┴─────────┘

Benchmark Code:

// Measure startup performance
const startTime = Date.now();

AppRegistry.registerComponent(appName, () => App);

// Log after first render
const FirstRenderTracker = () => {
  useEffect(() => {
    console.log(`First render: ${Date.now() - startTime}ms`);
  }, []);
  return null;
};

🎯 Best Practices

1. Gradual Migration

// Start with non-critical modules
const MyModule = Platform.select({
  ios: NativeModules.MyModuleOld,
  android: TurboModuleRegistry.get<Spec>('MyModule'),
});

2. Type Safety First

// Always define TypeScript specs
interface Spec extends TurboModule {
  readonly constantsToExport: {
    readonly apiUrl: string;
    readonly version: string;
  };
  methodWithCallback(callback: (result: string) => void): void;
}

3. Performance Testing

// Use React DevTools Profiler
import {Profiler} from 'react';

<Profiler id="MyComponent" onRender={(id, phase, duration) => {
  console.log(`${id} (${phase}) took ${duration}ms`);
}}>
  <MyComponent />
</Profiler>

🚀 Conclusion

The new React Native architecture isn’t just an incremental update—it’s a fundamental reimagining of how JavaScript and native code communicate. With:

  • Hermes providing faster startup and lower memory usage
  • JSI eliminating the bridge bottleneck
  • TurboModules offering type-safe, lazy-loaded native modules
  • Fabric bringing modern React features to mobile

…your React Native apps can now rival truly native performance while maintaining the developer experience we love.


This content originally appeared on DEV Community and was authored by Nader Alfakesh