React Native Neue Architektur: Fabric und TurboModules erklärt
AI generated
RN
native
React Native · JSI · Fabric · TurboModules
React Native Neue Architektur
Fabric und TurboModules ohne Bridge erklärt

Die Neue Architektur ersetzt die alte asynchrone Bridge mit JSON-Serialisierung durch JSI, ein direktes C++-Interface zwischen JavaScript und nativem Code. Fabric übernimmt als neuer Renderer die synchrone Layout-Berechnung, TurboModules laden native Module verzögert statt beim App-Start und Codegen erzeugt aus TypeScript-Spec-Dateien typsichere Schnittstellen für beide Plattformen.

19 Min. Lesezeit JSI · Fabric · TurboModules · Codegen · Migration React Native 0.74+ · newArchEnabled

1. Die alte Bridge: warum JSON-Serialisierung zum Bottleneck wurde

In der klassischen React-Native-Architektur liefen JavaScript-Thread, native UI-Thread und ein separater Shadow-Thread strikt getrennt nebeneinander. Kommunikation zwischen ihnen lief ausschließlich über die sogenannte Bridge: eine asynchrone Warteschlange, durch die jeder Aufruf, jedes Event und jede Layout-Änderung als JSON-String serialisiert, in Batches gesammelt und am Ende des Frames auf die jeweils andere Seite übertragen wurde. Diese Entkopplung klang zunächst elegant, weil sie JavaScript vor direktem Zugriff auf native Threads schützte. In der Praxis erzeugte sie jedoch messbaren Overhead, denn jedes Objekt musste zunächst in einen String verwandelt und auf der Gegenseite wieder geparst werden, bevor überhaupt etwas passieren konnte.

Das eigentliche Problem war nicht nur die Serialisierung selbst, sondern die erzwungene Asynchronität. Wollte eine Komponente die tatsächliche Höhe eines nativen Views kennen, bevor sie eine Animation startet, musste sie auf eine Antwort über die Bridge warten, die erst im nächsten Frame ankam. Synchrone native Aufrufe waren architektonisch schlicht unmöglich, weil die Bridge keine Rückantwort im selben Tick garantieren konnte. Bei komplexen Listen, Gesten oder Animationen summierten sich diese Wartezeiten zu spürbaren Rucklern, die Entwickler mit Workarounds wie InteractionManager oder manuellem Batching notdürftig umgingen, statt das eigentliche Problem zu lösen.

Hinzu kam, dass alle nativen Module beim App-Start eager instanziiert wurden, unabhängig davon, ob die JavaScript-Seite sie überhaupt jemals benötigte. Eine App mit vierzig eingebundenen Bibliotheken initialisierte vierzig native Module beim Kaltstart, selbst wenn nur fünf davon auf dem aktuellen Screen gebraucht wurden. Genau diese drei Schwachstellen, die JSON-Bridge, die erzwungene Asynchronität und das eager Loading, bildeten den Ausgangspunkt für die Neue Architektur, die JSI, Fabric und TurboModules gemeinsam adressieren.


// OLD ARCHITECTURE: everything crosses the async JSON bridge
import { NativeModules, findNodeHandle, UIManager } from 'react-native';

// A native call always returns via callback or promise, never synchronously
NativeModules.DeviceInfo.getBatteryLevel((error, level) => {
  if (error) {
    console.warn('Bridge call failed', error);
    return;
  }
  console.log('Battery level:', level);
});

// Measuring a native view requires a round trip through the bridge,
// the result only arrives in a later frame, never in the current tick
UIManager.measure(findNodeHandle(myViewRef.current), (x, y, width, height) => {
  // By the time this runs, the layout may already be stale
  console.log('Measured width:', width);
});

2. JSI: das JavaScript Interface als Fundament der Neuen Architektur

JSI, kurz für JavaScript Interface, ist die zentrale Innovation, auf der die gesamte Neue Architektur aufbaut. Statt Daten über eine serialisierte Warteschlange zu schicken, gibt JSI der JavaScript-Engine, ob Hermes, JavaScriptCore oder V8, direkten Zugriff auf C++-Objekte im Speicher. Ein sogenanntes HostObject wird der JavaScript-Runtime als ganz normales JavaScript-Objekt präsentiert, seine Methoden rufen aber tatsächlich C++-Code auf, ohne dass jemals ein JSON-String erzeugt wird. Der Aufruf passiert synchron, im selben Thread und im selben Tick, genau wie ein normaler Funktionsaufruf innerhalb von JavaScript.

Diese Eigenschaft ist der entscheidende Unterschied zur alten Bridge: Wo vorher ein Promise oder Callback nötig war, um überhaupt eine Antwort aus dem nativen Layer zu bekommen, kann Code unter der Neuen Architektur einen nativen Wert direkt und synchron auslesen, sofern die Operation das zulässt. Das eröffnet ganz neue Muster, etwa das synchrone Lesen von persistiertem Storage vor dem ersten Render oder das direkte Messen eines View-Layouts ohne Frame-Verzögerung. JSI ist dabei kein React-Native-spezifisches Konstrukt, sondern eine allgemeine C++-Schicht, die auch von anderen Bibliotheken wie Reanimated genutzt wird, um eigene direkte Bindungen an die JavaScript-Runtime aufzubauen.

Wichtig ist, dass JSI selbst kein Threading-Modell vorschreibt. Synchron heißt hier: kein Umweg über eine serialisierte Warteschlange, nicht zwangsläufig derselbe Thread für jede Operation. Rechenintensive native Arbeit lässt sich weiterhin auf einen Hintergrund-Thread auslagern, nur die Kommunikation selbst verliert den Bridge-Overhead. Für Entwickler bedeutet das: Die Neue Architektur ist kein reines Performance-Feature, sondern verändert grundsätzlich, welche Interaktionsmuster zwischen JavaScript und nativem Code überhaupt möglich sind.

3. Fabric: der neue Renderer statt UIManager und altem Shadow Tree

Fabric ist der Renderer der Neuen Architektur und ersetzt den alten UIManager zusammen mit dem klassischen Shadow-Tree-Mechanismus. In der alten Architektur existierte der Shadow Tree, der die Layout-Berechnung mit Yoga übernimmt, als eigenständige Struktur auf einem separaten Thread, die Ergebnisse wurden anschließend asynchron über die Bridge an den UIManager auf der nativen Seite übertragen. Fabric löst diese Trennung auf, indem der Shadow Tree jetzt in C++ implementiert ist und sowohl von JavaScript als auch von der nativen Seite direkt über JSI angesprochen werden kann, ohne Bridge-Umweg.

Der praktische Effekt: Layout-Berechnungen können synchron ablaufen, bevor der native View tatsächlich gezeichnet wird, was Flackern und Layout-Sprünge reduziert, die in der alten Architektur durch die asynchrone Übertragung entstehen konnten. Fabric erlaubt außerdem, dass eine Komponente direkten Zugriff auf einen nativen View-Ref bekommt, dessen Eigenschaften synchron gemessen werden können, statt auf eine spätere Callback-Antwort zu warten. Für Bibliotheken, die eng mit nativen Views interagieren, etwa Kamera-Komponenten, Karten oder Video-Player, bedeutet das spürbar weniger Race Conditions zwischen JavaScript-State und tatsächlichem nativen Rendering-Zustand.

Fabric bringt außerdem die technische Grundlage für React-18-Features wie Concurrent Rendering und Suspense in React Native mit, weil der C++ Shadow Tree konsistente, konsistent commitbare Zustände zwischen mehreren gleichzeitigen Render-Durchläufen halten kann. Eigene native UI-Komponenten müssen dafür allerdings als Fabric-Components mit einem ComponentDescriptor neu registriert werden, ein alter UIManager-basierter Custom View läuft unter Fabric nicht automatisch weiter, sondern benötigt eine angepasste Implementierung auf beiden Plattformen.

4. TurboModules: Lazy Loading statt eager NativeModules

TurboModules sind der direkte Nachfolger der alten NativeModules-API und lösen das Problem des eager Loadings, bei dem jedes registrierte native Modul beim App-Start instanziiert wurde, egal ob JavaScript es je aufrief. Unter der Neuen Architektur wird ein TurboModule erst dann tatsächlich instanziiert, wenn JavaScript zum ersten Mal darauf zugreift, über eine JSI-vermittelte Lazy-Loading-Logik. Das reduziert die Startzeit besonders bei Apps mit vielen Drittanbieter-Bibliotheken spürbar, weil nicht mehr jedes potenziell ungenutzte Modul den kritischen Pfad des Kaltstarts blockiert.

Der zweite große Unterschied betrifft Typsicherheit. Alte NativeModules basierten auf lose typisierten Bridge-Aufrufen, Tippfehler in Methodennamen oder falsche Argumenttypen fielen erst zur Laufzeit auf, oft mit kryptischen Absturzmeldungen. TurboModules werden stattdessen über eine TypeScript- oder Flow-Spec-Datei definiert, aus der Codegen zur Build-Zeit sowohl die JavaScript-Schnittstelle als auch native Interfaces für iOS und Android erzeugt. Weicht die tatsächliche native Implementierung vom Spec ab, schlägt der Build fehl, nicht erst die App zur Laufzeit beim Nutzer.


// NativeDeviceInfo.ts — TurboModule spec file, read by Codegen at build time
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  // Synchronous methods are explicitly marked, Codegen enforces this contract
  getBatteryLevelSync(): number;
  getDeviceModel(): Promise<string>;
  addListener(eventName: string): void;
  removeListeners(count: number): void;
}

export default TurboModuleRegistry.get<Spec>('DeviceInfo') as Spec | null;

5. Codegen: was aus der TypeScript-Spec-Datei wirklich entsteht

Codegen ist das Werkzeug, das die TypeScript-Spec-Datei in tatsächlich ausführbaren, plattformspezifischen Code übersetzt, und genau das macht TurboModules und Fabric-Components erst praktisch nutzbar. Aus einer einzigen Spec-Datei generiert Codegen auf der C++-Seite abstrakte HostObject-Klassen, auf der iOS-Seite Objective-C++-Protokolle, die eine Swift-Klasse implementieren muss, und auf der Android-Seite Java- oder Kotlin-Interfaces mit den exakt passenden Methodensignaturen. Der Entwickler schreibt die eigentliche Logik nur einmal pro Plattform, den gesamten Bridging-Boilerplate übernimmt Codegen vollautomatisch.

Damit Codegen eine Spec-Datei überhaupt findet, muss das Paket im codegenConfig-Abschnitt des package.json referenziert werden, inklusive Angabe, welche Verzeichnisse gescannt werden und wie das generierte C++-Modul heißen soll. Bei Monorepos oder eigenständigen nativen Modulen läuft Codegen typischerweise während pod install auf iOS beziehungsweise während des Gradle-Builds auf Android automatisch, das generierte Ergebnis landet in einem build-Verzeichnis und wird nicht manuell versioniert. Ändert sich die Spec-Datei, etwa durch eine neue Methode, muss lediglich neu gebaut werden, keine manuelle Bridging-Datei muss von Hand angepasst werden.


{
  "name": "react-native-device-info-turbo",
  "version": "1.0.0",
  "codegenConfig": {
    "name": "DeviceInfoSpec",
    "type": "modules",
    "jsSrcsDir": "src",
    "android": {
      "javaPackageName": "com.mironsoft.deviceinfo"
    },
    "ios": {
      "componentProvider": {}
    }
  },
  "peerDependencies": {
    "react-native": ">=0.74.0"
  }
}

6. Native Bindings: die Swift-Implementierung eines TurboModules

Nachdem Codegen aus der Spec-Datei das passende Objective-C++-Protokoll erzeugt hat, muss auf der iOS-Seite eine konkrete Swift-Klasse dieses Protokoll implementieren. Der entscheidende Unterschied zur alten NativeModules-API: Die Methodensignaturen sind jetzt vom Compiler erzwungen, nicht mehr nur durch Konvention verbunden. Fehlt eine Methode oder stimmt ein Rückgabetyp nicht mit der Spec überein, bricht bereits die Kompilierung ab, lange bevor der Code auf einem echten Gerät läuft.

Auf der Android-Seite läuft dasselbe Prinzip über ein von Codegen generiertes Java-Interface, das eine Kotlin-Klasse implementiert, inklusive eines TurboReactPackage-Eintrags, der dem Framework mitteilt, wie das Modul lazy instanziiert werden soll. In beiden Fällen bleibt die eigentliche Geschäftslogik plattformspezifischer Swift- oder Kotlin-Code, nur die Anbindung an JavaScript läuft jetzt über den generierten, typsicheren JSI-Layer statt über manuell gepflegte Bridge-Methoden mit RCT_EXPORT_METHOD-Makros.


// DeviceInfoModule.swift — implements the Codegen-generated protocol
import Foundation

@objc(DeviceInfoModule)
class DeviceInfoModule: NSObject, NativeDeviceInfoSpec {

  // Synchronous method, called directly through JSI, no bridge round trip
  @objc func getBatteryLevelSync() -> NSNumber {
    UIDevice.current.isBatteryMonitoringEnabled = true
    return NSNumber(value: UIDevice.current.batteryLevel)
  }

  @objc func getDeviceModel(_ resolve: @escaping RCTPromiseResolveBlock,
                             reject: @escaping RCTPromiseRejectBlock) {
    resolve(UIDevice.current.model)
  }

  @objc func addListener(_ eventName: String) {
    // Required by the Spec even if not used for this module
  }

  @objc func removeListeners(_ count: NSNumber) {
    // Required by the Spec even if not used for this module
  }
}

7. Migrationspfad: newArchEnabled in einer bestehenden App

Der Umstieg auf die Neue Architektur in einer gewachsenen App beginnt nicht mit dem Umschalten eines Flags, sondern mit einer Bestandsaufnahme aller genutzten Drittanbieter-Bibliotheken. Für jede Abhängigkeit muss geklärt werden, ob sie bereits TurboModule- beziehungsweise Fabric-kompatibel ist, ob sie nur über die alte Bridge funktioniert, oder ob sie eine Interop-Schicht nutzt, die beide Architekturen gleichzeitig unterstützt. Das React-Native-Directory-Projekt listet diesen Status für die meisten populären Pakete, das erspart das manuelle Durchforsten einzelner Issue-Tracker.

Ist die Kompatibilität geklärt, folgt die technische Aktivierung. Auf Android genügt meist das Setzen von newArchEnabled=true in gradle.properties, auf iOS wird die Umgebungsvariable RCT_NEW_ARCH_ENABLED beim Ausführen von pod install gesetzt, wodurch CocoaPods die Fabric- und TurboModule-fähigen Varianten der Podspecs auswählt. Nach der Aktivierung sollte zunächst in einer Entwicklungsumgebung getestet werden, mit vollständigem Neustart der Metro-Bundler-Caches, da alte, unter der klassischen Architektur kompilierte native Artefakte sonst zu unklaren Laufzeitfehlern führen können.

Ein realistischer Migrationsplan arbeitet schrittweise: zunächst die Aktivierung in einem Feature-Branch, danach ein vollständiger Regressionstest der kritischsten User-Flows, insbesondere Listen mit vielen Items, Gesten, Kamera- und Kartenintegrationen sowie alle selbst geschriebenen nativen Module. Erst wenn diese Bereiche stabil laufen, wird die Neue Architektur in einem Staging-Build an ein breiteres internes Testteam ausgerollt, bevor sie produktiv für alle Nutzer aktiv wird.


#!/usr/bin/env bash
# Enable the New Architecture on both platforms and rebuild native projects

# Android: set the flag in gradle.properties
echo "newArchEnabled=true" >> android/gradle.properties

# iOS: install pods with the New Architecture flag set
cd ios
RCT_NEW_ARCH_ENABLED=1 pod install
cd ..

# Clear stale caches from the old architecture before the first run
watchman watch-del-all
rm -rf $TMPDIR/metro-* $TMPDIR/react-*
npx react-native start --reset-cache

8. Typische Stolperstellen beim Umstieg auf die Neue Architektur

Die häufigste Fehlerquelle sind selbst geschriebene native UI-Komponenten, die noch direkt auf den alten UIManager zugreifen. Unter Fabric existiert diese API in der bisherigen Form nicht mehr, ein Custom View muss stattdessen als Fabric-Component mit eigenem ComponentDescriptor registriert werden. Wird dieser Schritt übersprungen, rendert die Komponente entweder gar nicht oder wirft zur Laufzeit eine Fehlermeldung, die auf den ersten Blick nichts mit der eigentlichen Ursache zu tun zu haben scheint.

Eine zweite verbreitete Stolperstelle betrifft View Flattening: Fabric optimiert die native View-Hierarchie aggressiver als der alte Renderer, wodurch Refs auf verschachtelte Views unter Umständen ein anderes natives Objekt zurückgeben als erwartet. Code, der sich auf eine bestimmte View-Hierarchie-Tiefe verlässt, etwa für manuelles Messen oder Animationen außerhalb von Reanimated, muss entsprechend angepasst werden. Auch NativeEventEmitter-Patterns aus alten Bibliotheken, die Events noch über die klassische Bridge-Queue verschicken, funktionieren unter der Neuen Architektur oft nur über eine Kompatibilitätsschicht mit spürbarem Zusatzaufwand.

Drittens lohnt sich ein genauer Blick auf Timing-sensiblen Code: Weil Fabric Layout-Messungen synchron statt über einen späteren Bridge-Callback liefert, können Effekte, die bisher bewusst auf die Verzögerung der alten Architektur gewartet haben, unter der Neuen Architektur zu früh oder in anderer Reihenfolge ausgelöst werden. Solche Stellen fallen meist erst durch manuelles Durchklicken kritischer Screens auf, automatisierte Tests decken reine Timing-Regressionen selten vollständig ab.

9. Alte Architektur und Neue Architektur im direkten Vergleich

Die folgende Tabelle stellt die zentralen Unterschiede zwischen der klassischen Bridge-Architektur und der Neuen Architektur mit JSI, Fabric und TurboModules gegenüber. Sie zeigt, warum die Neue Architektur kein reines Marketing-Label ist, sondern jede der drei Komponenten ein konkretes, in der alten Architektur strukturell unlösbares Problem adressiert.

Dimension Alte Architektur Neue Architektur
Kommunikationsschicht Bridge mit JSON-Serialisierung JSI: direkte C++-Bindungen
Native Aufrufe nur asynchron via Callback/Promise synchron möglich, wo sinnvoll
Modul-Laden eager, alle Module beim Start lazy via TurboModules
Renderer UIManager + asynchroner Shadow Tree Fabric mit C++ Shadow Tree
Typsicherheit manuelle Bridging-Deklarationen Codegen aus TypeScript-Spec

Der Vergleich macht deutlich, dass die Neue Architektur weniger eine einzelne Funktion als vielmehr ein zusammenhängendes System ist. JSI liefert das Fundament, Fabric nutzt es für den Renderer, TurboModules nutzen es für native Module, und Codegen sorgt dafür, dass beide Seiten dabei denselben, zur Build-Zeit geprüften Vertrag einhalten. Wer nur eine der drei Komponenten isoliert betrachtet, unterschätzt, wie eng Fabric und TurboModules technisch auf JSI aufbauen.

Mironsoft

React-Native-Apps für Magento-Shops, headless über REST und GraphQL angebunden

Bereit für die Neue Architektur oder noch auf der alten Bridge?

Wir bauen performante React-Native-Storefronts, die per REST- und GraphQL-API mit eurem Magento-Shop sprechen, und begleiten bestehende Apps beim Umstieg auf Fabric und TurboModules, von der Bibliotheks-Analyse bis zum stabilen Rollout.

Architektur-Audit

Bibliotheks-Kompatibilität prüfen, Fabric- und TurboModule-Lücken identifizieren

Migrations-Begleitung

newArchEnabled schrittweise aktivieren, Regressionstests, stabiler Staging-Rollout

Native-Module-Entwicklung

TurboModules mit Codegen-Spec in Swift und Kotlin für Magento-Anbindungen bauen

10. Zusammenfassung

Die Neue Architektur in React Native löst drei konkrete, strukturelle Probleme der alten Bridge-Ära: JSI ersetzt die JSON-Serialisierung durch direkte, synchrone C++-Bindungen zwischen JavaScript und nativem Code. Fabric ersetzt UIManager und den alten asynchronen Shadow Tree durch einen gemeinsamen, in C++ implementierten Renderer, der Layout synchron berechnet und enger mit nativen Views interagiert. TurboModules ersetzen NativeModules durch lazy geladene, über Codegen typsicher generierte Schnittstellen, die Fehler bereits zur Build-Zeit statt erst beim Nutzer aufdecken.

Für bestehende Apps ist der Umstieg kein Ein-Klick-Schalter, sondern ein Prozess: Bibliotheks-Kompatibilität prüfen, newArchEnabled schrittweise in Entwicklungsumgebung und Staging aktivieren, kritische Screens mit Listen, Gesten und eigenen nativen Modulen gezielt testen. Wer diesen Pfad sauber durchläuft, profitiert von spürbar kürzeren Startzeiten, robusterem Layout-Timing und einem Typsystem, das native Bugs schon vor dem ersten App-Start verhindert.

Neue Architektur, Fabric und TurboModules — Das Wichtigste auf einen Blick

JSI statt Bridge

Direkte C++-Bindungen ersetzen JSON-Serialisierung, synchrone native Aufrufe werden technisch möglich.

Fabric statt UIManager

C++ Shadow Tree berechnet Layout synchron, engere Interop mit nativen Views, Basis für Concurrent Rendering.

TurboModules statt NativeModules

Lazy Loading beim ersten JS-Zugriff statt eager Instanziierung aller Module beim App-Start.

Codegen aus TypeScript-Spec

Ein Spec-File erzeugt C++, Swift- und Kotlin-Interfaces, Vertragsbrüche fallen beim Build auf, nicht beim Nutzer.

11. FAQ: Neue Architektur, Fabric und TurboModules

1Was ist die Neue Architektur in React Native konkret?
Die Kombination aus JSI, Fabric und TurboModules, die die alte asynchrone Bridge mit JSON-Serialisierung durch direkte, synchrone C++-Bindungen ersetzt.
2Was genau ersetzt JSI?
Die klassische Bridge-Warteschlange mit JSON-Serialisierung. JSI gibt der JS-Engine direkten Zugriff auf C++-Objekte im Speicher.
3Was macht Fabric anders als der alte UIManager?
Fabric implementiert den Shadow Tree in C++ und teilt ihn per JSI. Layout wird synchron berechnet statt asynchron über die Bridge.
4Was sind TurboModules?
Nachfolger von NativeModules, lazy instanziiert beim ersten JS-Zugriff, mit per Codegen typsicher generierter Schnittstelle.
5Was generiert Codegen aus einer Spec-Datei?
C++-HostObject-Klassen, ein Objective-C++-Protokoll für iOS und ein Java/Kotlin-Interface für Android, mit exakt passenden Signaturen.
6Wie aktiviere ich newArchEnabled?
Android: newArchEnabled=true in gradle.properties. iOS: RCT_NEW_ARCH_ENABLED=1 beim pod install. Vorher Bibliotheks-Kompatibilität prüfen.
7Welche Bibliotheken bereiten am häufigsten Probleme?
Eigene native UI-Views mit direktem UIManager-Zugriff und Bibliotheken mit veralteten NativeEventEmitter-Patterns.
8Sind synchrone Aufrufe immer sinnvoll?
Nein, nur wo es passt. Rechenintensive Arbeit sollte weiterhin asynchron laufen, um den JS-Thread nicht zu blockieren.
9Muss ich eigene native Module neu schreiben?
Die Logik bleibt meist erhalten, aber die JS-Anbindung muss auf die Codegen-Spec umgestellt werden, eigene Views brauchen einen ComponentDescriptor.
10Ist die Neue Architektur schon Standard?
Ja, seit React Native 0.76 standardmäßig aktiv für neue Projekte, bestehende Apps benötigen weiterhin einen geplanten Migrationspfad.