{ sync: true }
callNative()
→ JSI
Turbo Modules

Turbo Modules Derinlemesine

Turbo ModulesJSICodegen

Codegen Spec’ten lazy init’e, sync/async seçiminden event listener yaşam döngüsüne kadar Turbo Modules’un production davranışı.

EG

Emre Gürbüz

23 Temmuz 2026 · 4 dk okuma

Turbo Modules, React Native New Architecture’ın native API katmanıdır. Tip sözleşmesi compile-time’da tanımlanır, binding JSI (doğrudan çağrı) üzerinden yapılır, init lazy’dir (ilk çağrıda yükleme).

“NativeModules’un yeni adı” değildir — keşif modelinden sözleşme modeline geçiştir. Eski dünyada NativeModules.Camera runtime’da vardı ya da yoktu; Turbo’da Spec yoksa build kırılır veya getEnforcing açıkça throw eder.

Neden Turbo Modules?

Eski Native Module sorunları:

  • Runtime keşif → yanlış method adı production sürprizi
  • Erken yükleme → kullanılmayan SDK cold start’ı şişirir
  • Serileştirme vergisi → her çağrı JSON bridge üzerinden
  • Tip güvenliği yok

Turbo Modules şunu getirir:

  • Spec (TypeScript/Flow) ile API tek kaynak
  • Codegen (kod üreteci) platform iskeleti üretir
  • Lazy init → cold start iyileşir
  • JSI → serileştirme köprüsü olmadan host object çağrısı

Spec: sözleşme olarak düşünün

Spec sadece TypeScript değil; native ekiplerle paylaşılan API kontratıdır:

import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  readonly getConstants?: () => {
    sdkVersion: string;
  };
  add(a: number, b: number): number; // sync
  fetchToken(userId: string): Promise<string>; // async
}

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

getEnforcing modül yoksa throw eder — sessiz undefined anti-pattern’ini öldürür. Optional için TurboModuleRegistry.get kullanın.

Codegen yapılandırması

package.json veya app config içinde codegenConfig:

{
  "name": "NativeSampleModuleSpec",
  "type": "modules",
  "jsSrcsDir": "src/specs",
  "android": { "javaPackageName": "com.example.sample" }
}

CI tuzakları:

  • Spec yolu yanlış → codegen çalışmaz
  • New Arch kapalı build → generated sınıflar farklı
  • Monorepo’da path kırılır
  • Registry string adı ile native module name uyuşmazlığı

Codegen çıktısının CI’da üretildiğini doğrulayın.

Sync vs async

Metot tipiNe zamanRisk
SyncKüçük okuma: flag, path, cache hitJS thread bloklanır
Async (Promise)Disk, ağ, kamera, permissionDaha güvenli varsayılan
Event / callbackStream, sensor, pushremoveListeners unutulursa leak

Varsayılan async olsun. Sync’i yalnızca ölçülmüş hot path için kullanın. Sync metot içinde disk/network = ANR ve frame drop.

getConstants içine ağır iş koymayın — constants gerçekten sabit olmalı.

Lazy init: kazanç ve ilk çağrı spike’ı

Kullanılmayan modül yüklenmez → cold start iyileşir. Ama ağır SDK (ML, harita, ödeme) ilk dokunuşta spike üretebilir.

Çözüm: Explicit warmup(): Promise<void> async metodu; splash veya onboarding’de arka planda çağırın.

Android implementasyon iskeleti

Codegen base class’a extend edersiniz — elle JNI binding yazmazsınız:

public class NativeSampleModule extends NativeSampleModuleSpec {
  public NativeSampleModule(ReactApplicationContext ctx) {
    super(ctx);
  }

  @Override
  public double add(double a, double b) {
    return a + b;
  }

  @Override
  public void fetchToken(String userId, Promise promise) {
    // async: native thread'de iş, promise resolve/reject
  }
}

iOS’ta generated Spec protocol’ü implement edilir. Android + iOS davranış parity testleri şart.

Eski Native Module’den migrasyon

  1. Mevcut API yüzeyini Spec’e dökün — deprecated metotları şimdi kaldırın
  2. Android/iOS implementasyon yazın; E2E ile doğrulayın
  3. JS import: NativeModules.Foo → Spec default export
  4. Feature flag ile eski/yeni paralel (riskli modüller)
  5. Event listener audit: addListener / removeListeners
  6. ProGuard keep: generated sınıflar

Interop geçici köprüdür — yeni modül eklemeyin; migrate edin.

Sık hatalar

  • Spec’te number, native’de int/long/double karışıklığı
  • Event listener remove etmemek → leak
  • Codegen adı ile registry string uyuşmazlığı
  • Turbo Module yazıp Fabric component unutmak (view’lar ayrı Spec)
  • Sync metotları her yere yaymak
  • New Arch kapalı ortamda test etmemek

Production checklist

  • codegenConfig doğru; CI’da çıktı doğrulanıyor
  • Spec tek kaynak
  • Sync metotlar auditlendi
  • Init side-effect yok veya explicit warmup() var
  • Android + iOS aynı davranış testleri
  • Event listener lifecycle test edildi
  • New Arch kapalı interop smoke (geçiş dönemi)
  • ProGuard keep generated sınıfları kapsıyor

Özet

Turbo Modules, native sınırı dokümantasyondan çıkarıp derleyiciye verir. Performans JSI’den, güvenilirlik codegen’den, startup lazy init’ten gelir. Spec’i API review sürecine dahil edin; her native metot ekleme PR’da Spec diff’i olsun.


Diğer yazılar