Native Modules

Native Modules vs Turbo Modules

Native ModulesTurbo Modules

Klasik NativeModules API ile codegen tabanlı Turbo Modules karşılaştırması: performans, migrasyon stratejisi ve ne zaman dönüştürüleceği.

EG

Emre Gürbüz

30 Temmuz 2026 · 4 dk okuma

React Native’de “JS’ten native çağır” ihtiyacı iki nesil API ile karşılanır: klasik Native Modules ve New Architecture’ın Turbo Modules’u. İkisi aynı problemi çözer gibi görünür; sözleşme, keşif, threading ve tooling kökten farklıdır.

Karar “hepsini migrate et” veya “legacy yeter” değil; çağrı sıklığı, tip riski ve New Arch roadmap’ine göre önceliktir.

Klasik Native Modules: runtime keşif

Eski stil native çağrı örneği:

import { NativeModules } from 'react-native';
const { DeviceInfo } = NativeModules;
await DeviceInfo.getBatteryLevel();

Native taraf uygulama başlangıcında module map’i JS’e açar. Bridge (eski JSON köprüsü) üzerinden async mesaj gider, cevap Promise ile döner.

Artı: basit model, bol dokümantasyon, eski kütüphaneler hazır. Eksi: yanlış modül adı → undefined (compile-time yakalanmaz); performans bridge ile sınırlı; New Arch’da interop (geçici köprü katmanı) maliyeti.

getConstants() erken hydrate için kullanışlıdır ama eager init maliyeti yaratır.

Turbo Modules: compile-time sözleşme

Spec üzerinden tip güvenli çağrı:

import NativeDeviceInfo from './NativeDeviceInfo';
const level = await NativeDeviceInfo.getBatteryLevel();

Turbo Modules Spec-first yaklaşım kullanır: TypeScript/Flow ile API tanımlarsınız, codegen (kod üreteci) platform iskeletini üretir. JSI (doğrudan çağrı) ile lazy init — modül ilk çağrıda yüklenir. TurboModuleRegistry.getEnforcing fail-fast sunar: modül yoksa erken patlar, sessiz undefined değil.

Sync çağrı mümkündür — dikkatli kullanıldığında. Storage okuma gibi milisaniye altı işler için bridge overhead’i kalkar. Sync JS thread’i bloklama riski taşır.

Derin karşılaştırma

BoyutNative ModulesTurbo Modules
KeşifRuntime module mapSpec + codegen
TaşımaBridge JSONJSI binding
InitGenelde eagerLazy (ilk çağrıda)
Tip güvenliğiZayıfGüçlü (Spec)
Sync çağrıPratikte yokMümkün (disiplin şart)
New Arch uyumuInteropBirinci sınıf
Öğrenme eğrisiDüşükOrta-yüksek

Interop “çalışıyor” demek “optimal” demek değildir. Hot path’teki legacy modül her çağrıda ekstra maliyet öder.

Performans: sayılarla düşünmek

Bridge async çağrısı tipik olarak yüzlerce mikrosaniye ile birkaç milisaniye overhead taşır. Saniyede 10 çağrı tolere edilir; saniyede 1000 analytics event bridge üzerinden frame drop üretir.

Sync Turbo serileştirmeyi sıfırlar; native implementasyonunuz 5ms sürüyorsa JS thread 5ms bloklanır. Kazanç her zaman “Turbo’ya geç” değil; doğru API + doğru thread’dir.

Ne zaman migrate etmeli?

Hemen düşünün:
  • Sık çağrılan API: storage, feature flag, analytics batch
  • New Arch 6 ay içinde production’da
  • Kütüphane yayınlıyorsunuz
  • Tip hataları production’a sızıyor
  • Sync okuma ihtiyacı var
Bekleyebilirsiniz:
  • Yılda bir kez çağrılan sarmalayıcı
  • Yakında silinecek ekran
  • Vendor SDK henüz New Arch dokümantasyonu sunmuyor
  • Surface küçük ve crash riski sıfır

Karar: çağrı_sıklığı × tip_riski × New_Arch_hedefi. Yüksek × yüksek × evet = migrate now.

Migrasyon pattern’i

Birinci kural: API davranış parity’si. Spec’i mevcut API’den çıkarın; JS tüketicileri değişmemeli.

  1. Tüm NativeModules.* envanteri; hot path’leri işaretleyin
  2. Spec yazın + codegen (Android + iOS)
  3. Facade’da Turbo + legacy fallback
  4. Feature flag ile cohort rollout
  5. Metrikler stabil → legacy kaldırın
  6. ESLint: doğrudan NativeModules import yasak

Facade örneği — Turbo varsa onu, yoksa legacy kullanır:

import { NativeModules } from 'react-native';
import NativeSample from './specs/NativeSample';

export function add(a: number, b: number): number {
  if (NativeSample) {
    return NativeSample.add(a, b);
  }
  return NativeModules.SampleLegacy.add(a, b);
}

Codegen çıktısını commitlemeyin — her build’de üretilsin. CI’da codegen adımını quality gate’e ekleyin.

View’lar ayrı konu

Native module Turbo’ya geçmek, native component’in Fabric’e geçmesi demek değildir. Eski ViewManager → Fabric Spec ayrı migrasyon. Sadece Turbo’ya geçip custom view’ları Paper’da bırakmak hibrit acı üretir.

Platform parity ve R8

Nullable dönüş, array vs object, enum representation platformlar arası test edilmeli.

R8 obfuscation Turbo kayıt sınıflarını silebilir. proguard-rules.pro’da codegen keep kuralları güncel tutun. Release’de “modül bulunamadı” çoğu zaman keep eksikliğidir.

Production checklist

  • Tüm NativeModules.* envanteri çıkarıldı
  • Hot path’ler önceliklendirildi
  • Spec + codegen Android/iOS yeşil
  • Facade + legacy fallback test edildi
  • Interop’tan çıkış tarihi backlog’da
  • R8/ProGuard keep güncel
  • New Arch açık/kapalı matrix test
  • Custom view varsa Fabric planı var
  • ESLint: NativeModules import yasak

Özet

Native Modules RN’i büyüttü; Turbo Modules onu ölçeklenebilir native sınıra taşır. Legacy’yi şeytanlaştırmak yerine hangi yüzeyin hâlâ bridge ekonomisinde yaşadığını bilerek migrate edin. Interop geçici köprüdür — kalıcı mimari değil.


Diğer yazılar