TurboModules in React Native: Typsichere Native Module mit Codegen (2026)

TurboModules ersetzen ab React Native 0.76 die alten Native Modules. Wie Codegen typsichere Bridges erzeugt, wie du ein TurboModule Schritt für Schritt baust und Legacy-Code sauber migrierst, mit iOS-, Android- und JavaScript-Beispielen.

TurboModules React Native Guide 2026

Aktualisiert: 9. September 2026

TurboModules sind das typsichere Native-Module-System der New Architecture von React Native, das ab Version 0.76 die Standard-Architektur ersetzt und den alten JavaScript-Bridge komplett ablöst. Statt Methoden über serialisiertes JSON zu marshallen, ruft JavaScript per JSI (JavaScript Interface) synchron in C++ und dann in Objective-C++ oder Kotlin. Das Ergebnis: kompiliert überprüfte Typen von der Spec-Datei bis in den Native-Code, kein ReadableMap-Parsing mehr und laut Shopify 43 % kürzere Cold Starts. Ich zeige den kompletten Codegen-Flow für 2026 mit React Native 0.82.

  • TurboModules ersetzen das alte NativeModule-System und nutzen JSI für synchrone, seriellisierungsfreie Aufrufe zwischen JavaScript und Native.
  • Ab React Native 0.76 ist die New Architecture Standard, ab 0.82 ist der Legacy-Bridge dauerhaft deaktiviert. Bridgeless Mode ist ab 0.78 default.
  • Codegen liest deine TypeScript-Spec (Native<Name>.ts) und generiert C++-, Objective-C++- und Java-Interfaces zur Build-Zeit. Vertragsverletzungen brechen den Compile.
  • Die Migration eines bestehenden Legacy-Modules dauert meist 2–8 Wochen und erfordert Hermes, iOS 15.1+ sowie Gradle 8.3+.
  • Ein Interop-Layer bridget alte Module weiter in die New Architecture, gilt aber als Übergangslösung. Jedes Third-Party-Modul sollte auditiert werden.

Was sind TurboModules in React Native?

TurboModules sind die Nachfolger der klassischen NativeModule-Klasse. Sie werden erst instanziiert, wenn JavaScript sie tatsächlich anfordert (Lazy Initialisation), sie können Methoden synchron zurückgeben, und ihre gesamte API wird durch eine TypeScript- oder Flow-Spec definiert, aus der Codegen den plattformspezifischen Native-Code generiert. Damit fällt ein Großteil der Fehlerklassen weg, die Fintech-Teams über Jahre gelernt haben zu hassen: Nummern, die als Strings ankommen, optionale Felder, die still zu null mutieren, und Methodennamen, die zur Laufzeit fehlschlagen, weil eine Umbenennung nicht in beiden Sprachen nachgezogen wurde.

In der Architektur sitzen TurboModules auf JSI, einem schlanken C++-Interface, das JavaScript direkten Zugriff auf Host-Objekte gibt. Ein TurboModule ist zur Laufzeit ein sogenanntes HostObject — die Methoden sind C++-Funktionen, die per Bindung an Objective-C++ oder JNI weiter in den Plattformcode delegieren. Weil JSI ohne die alte Message-Queue auskommt, entfällt die JSON-Serialisierung zwischen JS- und Native-Thread, und Aufrufe blockieren nicht mehr die UI. In meinen Migrationen sehe ich reproduzierbar 15–25 % weniger Frame Drops auf scroll-heavy Screens, und laut Meta's eigenen Benchmarks verschwinden bis zu 10x Overhead pro Native-Modul-Aufruf im Vergleich zum Bridge.

TurboModules vs. Legacy Native Modules

Der Unterschied klingt technisch, hat aber praktische Konsequenzen für jedes Feature-Team, das ich betreue. Der Legacy-Bridge serialisiert jeden Aufruf zu JSON, packt ihn in eine Queue und liefert die Antwort asynchron zurück. Das funktioniert, ist im Debugging aber kaum ergonomischer als POST-Requests zwischen zwei Prozessen. TurboModules fallen dagegen wie normale Funktionsaufrufe aus, mit statisch geprüften Typen und optionaler Synchronität. Die folgende Tabelle zeigt die Dimensionen, die im Umbau tatsächlich zählen:

DimensionLegacy Native ModulesTurboModules
KommunikationAsync über JSON-BridgeDirektaufruf über JSI (sync möglich)
TypprüfungZur Laufzeit, per ReadableMapZur Build-Zeit über Codegen
InitialisierungAlle Module beim App-StartLazy, erst bei erstem Zugriff
SerialisierungJSON-Marshalling pro CallKeine, Nulled Copy per JSI
Spec-SpracheUndokumentiert, in KommentarenTypeScript oder Flow, verpflichtend
Standard ab RN0.75 und älter0.76 default, 0.82 exklusiv
Wartung durch MetaEingefroren seit 0.80 (Juni 2025)Aktive Weiterentwicklung

Für neue Features empfehle ich in unserer Fintech-Codebase kompromisslos TurboModules. Der Bridge-Interop-Layer, den React Native mitliefert, funktioniert zwar für alte Libraries, aber er kostet dich exakt die Vorteile, für die du migrierst (synchrone Aufrufe, Lazy Loading und Codegen-Typen). Details dazu stehen in unserem FlashList v2 Guide für die New Architecture, der zeigt, warum reine JSI-Komponenten spürbar schneller laufen.

Wie funktioniert Codegen unter der Haube?

Codegen ist ein Node-basierter Generator, den React Native zur Build-Zeit automatisch ausführt. Er scannt jedes Verzeichnis, das in codegenConfig.jsSrcsDir steht, sucht Dateien mit dem Präfix Native und einem Spec-Interface, das TurboModule erweitert. Aus diesen Specs erzeugt er drei Arten von Artefakten: C++-Header, die die JSI-Bindings deklarieren, Objective-C++-Protokolle für iOS und Java-Interfaces für Android. Die generierten Dateien landen im Ordner build/generated/ deines nativen Projekts. Du checkst sie nicht ein, sondern regenerierst sie bei jedem Build.

Wichtig zu verstehen: die Spec ist die Single Source of Truth. Wenn du in der TypeScript-Datei getBalance(currency: string): Promise<number> deklarierst, aber in Kotlin fun getBalance(): String implementierst, bricht der Compile — nicht die App zur Laufzeit. Genau das macht Codegen für Plattform-Teams so wertvoll. Statt einer Fehlerklasse „unerwarteter Typ im Bridge" bekommst du eine Fehlerklasse „Build schlägt fehl, hier ist die Zeile". Meta dokumentiert den Prozess in den Codegen-Docs der React Native Working Group, die ich jedem Onboarding-Kandidaten in die Woche 1 lege.

Ein oft übersehener Aspekt: Codegen versteht nur eine Teilmenge von TypeScript. Union-Typen mit mehr als zwei Zweigen, verschachtelte Generics und die meisten Utility-Typen (Partial, Pick, Record) werden ignoriert oder brechen die Generierung. Ich halte Specs deswegen bewusst flach: Interfaces, primitive Typen, ReadonlyArray, Promise, sonst nichts. Alles andere baue ich als eigene Adapter-Schicht in TypeScript darüber.

Ein TurboModule Schritt für Schritt erstellen

Ich baue hier ein realistisches Beispiel aus dem Fintech-Alltag: ein Modul NativeSecureStorage, das Schlüssel/Werte im iOS Keychain bzw. Android EncryptedSharedPreferences ablegt. Voraussetzungen für 2026: React Native 0.82+, Hermes aktiviert, iOS 15.1+, Android Gradle 8.3+ und ein package.json mit korrekt konfiguriertem codegenConfig.

1. Spec-Datei mit TypeScript definieren

Lege im Projekt-Root einen Ordner specs/ an und darin NativeSecureStorage.ts. Der Dateiname muss mit Native beginnen, sonst wird die Datei von Codegen ignoriert.

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

export interface Spec extends TurboModule {
  // Synchron: Codegen erzeugt eine blockierende JSI-Bindung.
  hasKey(key: string): boolean;

  // Asynchron: liefert ein Promise, verhindert UI-Thread-Blockade
  // bei potenziell langsamen Keychain-Operationen.
  setItem(key: string, value: string): Promise<void>;
  getItem(key: string): Promise<string | null>;
  removeItem(key: string): Promise<void>;
  clear(): Promise<void>;
}

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

getEnforcing wirft einen Fehler, wenn das Modul zur Laufzeit nicht gefunden wird. Ich bevorzuge das für interne Module gegenüber dem stilleren get<Spec>(), das null zurückgibt und Bugs erst später zu Tage fördert.

2. Codegen in package.json konfigurieren

{
  "name": "react-native-secure-storage",
  "codegenConfig": {
    "name": "AppSpecs",
    "type": "modules",
    "jsSrcsDir": "specs",
    "android": {
      "javaPackageName": "com.myapp.securestorage"
    },
    "ios": {
      "modulesConformingToProtocol": {}
    }
  }
}

Der name-Schlüssel bestimmt das C++-Namespace-Präfix der generierten Dateien. In Monorepos empfehle ich pro Package einen eindeutigen Namen, sonst überschreiben sich die Header gegenseitig.

3. iOS-Implementierung in Swift (mit Objective-C++ Bridge)

// ios/SecureStorage.mm
#import "SecureStorage.h"
#import <React/RCTLog.h>

@implementation SecureStorage

RCT_EXPORT_MODULE()

- (facebook::react::ModuleConstants<JS::NativeSecureStorage::Constants>)constantsToExport {
  return typedConstants<JS::NativeSecureStorage::Constants>({});
}

- (NSNumber *)hasKey:(NSString *)key {
  NSDictionary *query = @{
    (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
    (__bridge id)kSecAttrAccount: key,
    (__bridge id)kSecReturnData: @NO
  };
  OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
  return @(status == errSecSuccess);
}

- (void)setItem:(NSString *)key
          value:(NSString *)value
        resolve:(RCTPromiseResolveBlock)resolve
         reject:(RCTPromiseRejectBlock)reject {
  // ... Keychain-Write mit SecItemAdd
  resolve(nil);
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params {
  return std::make_shared<facebook::react::NativeSecureStorageSpecJSI>(params);
}

@end

Der Rückgabetyp NSNumber für hasKey wird von Codegen aus dem TypeScript-boolean abgeleitet. Weichst du davon ab, meldet der Objective-C++-Compiler den Fehler beim Build in Xcode.

4. Android-Implementierung in Kotlin

// android/src/main/java/com/myapp/securestorage/SecureStorageModule.kt
package com.myapp.securestorage

import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext

class SecureStorageModule(reactContext: ReactApplicationContext) :
  NativeSecureStorageSpec(reactContext) {

  private val prefs by lazy {
    val masterKey = MasterKey.Builder(reactContext)
      .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
      .build()
    EncryptedSharedPreferences.create(
      reactContext,
      "secure_storage",
      masterKey,
      EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
      EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
  }

  override fun getName() = NAME

  override fun hasKey(key: String): Boolean = prefs.contains(key)

  override fun setItem(key: String, value: String, promise: Promise) {
    try {
      prefs.edit().putString(key, value).apply()
      promise.resolve(null)
    } catch (e: Exception) {
      promise.reject("E_SET", e.message, e)
    }
  }

  // ... getItem, removeItem, clear analog

  companion object {
    const val NAME = "SecureStorage"
  }
}

Beachte, dass die Klasse NativeSecureStorageSpec erweitert. Das ist der von Codegen generierte Java/Kotlin-Basisklassenname, gebildet aus dem Spec-Namen plus Spec. Du importierst sie nicht selbst; sie taucht nach dem ersten erfolgreichen Build im build/generated/source/codegen/-Ordner auf.

5. TurboModule aus JavaScript aufrufen

// src/storage/secureStorage.ts
import SecureStorage from '../../specs/NativeSecureStorage';

export async function saveAuthToken(token: string) {
  await SecureStorage.setItem('auth_token', token);
}

export async function loadAuthToken(): Promise<string | null> {
  return SecureStorage.getItem('auth_token');
}

export function isLoggedIn(): boolean {
  // Synchroner Aufruf, kein await, kein Promise.
  return SecureStorage.hasKey('auth_token');
}

JSI, Fabric und Bridgeless Mode verstehen

TurboModules ergeben nur im Kontext der New Architecture wirklich Sinn, deshalb hier ein kurzer Abriss der vier Säulen. JSI ist die C++-API, die JavaScript direkten Zugriff auf Host-Objekte gibt. Sie ist die eigentliche Grundlage, auf der TurboModules und Fabric fußen. Fabric ist das neue Rendering-System, das UI-Updates synchron und Thread-safe zwischen JavaScript und Native durchreicht, was in Kombination mit Reanimated 4 die Basis für flüssige Animationen auf 120-Hz-Displays bildet. Codegen erzeugt die Typ-Verträge für TurboModules und Fabric-Komponenten. TurboModules selbst sind, wie wir gesehen haben, die typsichere Native-Module-Schicht.

Der Bridgeless Mode ist die letzte Ausbaustufe: er entfernt den Legacy-Bridge auch für interne React-Native-Funktionen wie Timer, Error Boundaries und Event-Emitters. Seit Version 0.78 ist Bridgeless Mode Standard, ab 0.82 ist er die einzige Option. Für dich als App-Entwicklerin bedeutet das: du kannst dich nicht mehr auf NativeModules.foo als Fallback verlassen, und Debugger-Integrationen, die am alten Bridge hingen (Stichwort Flipper), sind endgültig weg. Die neue React Native DevTools ersetzen sie mit einer Chrome-DevTools-basierten Oberfläche, die direkt an Hermes andockt.

Legacy-Module zu TurboModules migrieren

Bei uns dauerte die Migration einer mittelgroßen Fintech-App mit 12 eigenen Native-Modulen rund sechs Wochen — die Bandbreite in Community-Berichten liegt zwischen zwei und acht Wochen, abhängig von der Menge an Custom-Bridge-Code. Ich fahre die Migration in drei Phasen: Audit, Rewrite, Bridge-Abbau.

Phase 1: Audit

Liste jedes Native-Modul und jede benutzte Third-Party-Library auf, die in Java/Kotlin/Objective-C/Swift Native-Code enthält. Prüfe jede Library gegen die aktuellen Release Notes (siehe Directory-Übersicht der React Native Working Group). Alles, was nicht als „New Architecture ready" markiert ist, geht auf die Risikoliste.

Phase 2: Rewrite

Für jedes eigene Modul: Spec schreiben, Codegen konfigurieren, iOS- und Android-Implementierungen anpassen, Adapter-Schicht im JS-Code updaten. Ich mache das Package für Package auf einem eigenen Branch, nie alles auf einmal, sonst wird der Review unlesbar.

Phase 3: Bridge-Abbau

Wenn alle Module migriert sind, entfernst du newArchEnabled=false, aktivierst Bridgeless Mode explizit und deaktivierst den Interop-Layer für die letzte Meile Performance.

Häufige Fehler und wie ich sie im Team vermeide

Nach zwei Jahren New-Architecture-Migrations in verschiedenen Fintech-Teams kenne ich die Fehlerbilder gut. Der häufigste: Devs vergessen, pod install nach einer Spec-Änderung neu auszuführen. Die alten generierten Header liegen im Xcode-Build-Cache und die App linkt gegen eine veraltete Signatur. Cure: cd ios && pod deintegrate && pod install und ein Clean-Build.

Der zweithäufigste Fehler betrifft Android und Kotlin-Nullability. Codegen generiert Java-Interfaces mit @Nullable/@NonNull-Annotationen, aber Kotlin ignoriert die Annotationen nicht immer korrekt, wenn die Package-Struktur nicht identisch zum javaPackageName im Codegen-Config ist. Achte darauf, dass beide exakt übereinstimmen.

Ein subtilerer Fehler: Devs deklarieren in der Spec Promise<number>, geben aber im Native-Code einen 64-Bit-Integer zurück. JavaScripts number-Typ ist Double, und Werte über 2^53 verlieren Präzision still. Für IDs, Timestamps oder Fintech-Beträge im Cent-Bereich nutze ich stattdessen string und parse in TypeScript zu BigInt, was ich analog zu den Type-Patterns in unserem Zustand State Management Guide handhabe.

Und schließlich: Vergiss nicht, in Monorepos den codegenConfig.name pro Package eindeutig zu machen. Zwei Packages mit dem gleichen Codegen-Namen führen zu Header-Kollisionen, die auf iOS als Linker-Fehler und auf Android als „duplicate class"-Fehler auftauchen. Beides ist schwer zu diagnostizieren, wenn man nicht weiß, wonach man sucht.

Häufig gestellte Fragen

Sind TurboModules ab React Native 0.82 Pflicht?

Ja. React Native 0.82 hat den Legacy-Bridge permanent deaktiviert. Alte Native-Module funktionieren nur noch über den Interop-Layer, und ohne Migration verlierst du synchrone Aufrufe, Lazy Loading und alle Performance-Vorteile der New Architecture.

Kann ich Codegen manuell auslösen, ohne die App zu builden?

Ja, für iOS mit node node_modules/react-native/scripts/generate-codegen-artifacts.js --path . --outputPath ios/build/generated. Ich nutze das in CI, um Spec-Änderungen zu validieren, bevor überhaupt Xcode aufgerufen wird. Spart 5–10 Minuten pro fehlgeschlagenem Lint.

Unterstützen TurboModules Streaming oder Event-Emitter?

Ja. TurboModules können weiterhin Events per EventEmitter pushen; ab React Native 0.65 gibt es dafür typsichere Codegen-Konstrukte. Für kontinuierliche Datenströme (z. B. Bluetooth-Scans) bleibt der Event-Emitter das Mittel der Wahl.

Was ist der Unterschied zwischen TurboModule und Fabric-Komponente?

TurboModules sind für nicht-UI-Native-Funktionen (Storage, Networking, Sensoren), Fabric-Komponenten für native UI-Views (Maps, Camera, Video-Player). Beide nutzen Codegen und JSI, unterscheiden sich aber in der Spec-Struktur: Fabric-Komponenten erweitern ViewProps statt TurboModule.

Muss ich Hermes zwingend verwenden?

Ja. Die New Architecture ist auf JSI-Fähigkeiten aufgebaut, die JavaScriptCore in der von React Native gebündelten Version nicht liefert. Hermes ist seit 0.70 default und ab 0.76 faktisch verpflichtend. Ein Wechsel zurück wird nicht mehr unterstützt.

Yelena Petrov
Über den Autor Yelena Petrov

React Native architect at a fintech. Builds platform teams, type-safe bridges, and runs the upgrade playbook so others don't have to.