Nova Arquitetura React Native 2026: Guia Completo de Migração para Fabric, TurboModules e JSI

Guia prático e atualizado para migrar seu app React Native para a Nova Arquitetura em 2026: Fabric, TurboModules, JSI e Codegen com exemplos para Expo e bare.

Nova Arquitetura React Native: Migração 2026

Vou ser direto: em 2026, migrar para a Nova Arquitetura do React Native deixou de ser uma escolha estratégica e virou uma obrigação técnica. Com o React Native 0.76 tornando o Fabric padrão, o SDK 54 do Expo sendo o último a permitir o opt-out e a versão 0.82 removendo definitivamente o Bridge legado, qualquer projeto que ainda depende da arquitetura antiga está acumulando dívida que vai explodir nos próximos releases.

Já passei por essa migração em três apps de tamanhos diferentes (um deles com mais de 40 telas e umas 15 dependências nativas), e a verdade é que a documentação oficial cobre só metade da história. O resto a gente descobre na marra.

Este guia foi escrito justamente pra resolver, num único lugar, todas as dúvidas que aparecem quando uma equipe se prepara para a migração: o que muda na prática, como auditar dependências, como habilitar as flags em projetos bare e Expo, como converter um Native Module antigo em um TurboModule, como validar Fabric em produção e — talvez o mais importante — como executar um rollout gradual sem quebrar usuários.

O que é a Nova Arquitetura do React Native

A Nova Arquitetura é a reescrita do core do React Native. Ela substitui a comunicação assíncrona baseada em Bridge (com aquela serialização JSON entre threads que sempre foi um gargalo) por chamadas diretas e síncronas via JSI. Quatro pilares trabalham em conjunto:

  • JSI (JavaScript Interface): uma API C++ leve que permite ao runtime JavaScript manter referências diretas a objetos C++ e vice-versa. Sem JSON, sem fila assíncrona, sem serialização.
  • TurboModules: a nova geração de Native Modules, com inicialização lazy e invocação síncrona via JSI. Substituem o sistema NativeModules baseado no Bridge.
  • Fabric: o novo renderizador, escrito em C++, com árvore de UI imutável, renderização interruptível e suporte nativo ao modo concorrente do React 18+.
  • Codegen: ferramenta que gera, em tempo de build, bindings type-safe entre o JavaScript (TypeScript spec) e o código nativo (Java/Kotlin/Objective-C++/Swift), eliminando uma classe inteira de bugs de runtime.

O efeito combinado é mensurável — e, sinceramente, surpreendente. Migrações em produção reportam cold starts até 43% mais rápidos, renderização até 39% mais rápida e redução de 20–30% no uso de memória. As chamadas de módulos nativos chegam a ser 10x mais rápidas sem o overhead de serialização do Bridge.

Por que migrar agora (e não em 2027)

Adiar tem custo. O ecossistema está se movendo rápido e os indicadores são bem claros:

  • React Native 0.82 remove completamente a arquitetura legada. Não há flag para desabilitar.
  • Expo SDK 55+ (lançamentos a partir de 2026) executa exclusivamente na Nova Arquitetura. SDK 54 é o último que aceita newArchEnabled: false.
  • Reanimated 4 (estável desde 2025) só funciona na Nova Arquitetura. Quem ficar no Paper trava no Reanimated 3.x sem updates de segurança.
  • Bibliotecas como FlashList v2, Vision Camera 4+, Skia atual e React Navigation 7.2+ assumem Fabric.
  • Patches de segurança e correções de bugs do core deixam de ser portados para versões antigas em poucos meses.

Em outras palavras: ou você migra agora, com calma, ou vai migrar em pânico no meio de um upgrade forçado.

Pré-requisitos antes de começar

Antes de tocar em qualquer linha de código, valide o checklist abaixo no seu projeto. Pular essa parte é a forma mais comum de transformar uma migração de 3 dias num pesadelo de 3 semanas.

1. Hermes habilitado

O JSI depende de capacidades específicas do Hermes. JavaScriptCore não roda na Nova Arquitetura — ponto final. Verifique no android/app/build.gradle:

project.ext.react = [
    enableHermes: true
]

E no ios/Podfile:

use_react_native!(
  :path => config[:reactNativePath],
  :hermes_enabled => true
)

Em projetos Expo modernos, Hermes é o padrão e essa etapa já está pronta.

2. Versão do React Native

Se o seu projeto está mais de 4 versões atrás da release atual, considere fazer a atualização incremental antes da migração. Use o React Native Upgrade Helper para gerar o diff entre a sua versão e a 0.81+ (recomendada para iniciar a migração).

3. Auditoria de dependências

Cada pacote com código nativo precisa ser verificado. Rode:

npx react-native-community/cli doctor
npm outdated

Em seguida, abra o React Native Directory e filtre por "New Architecture" para confirmar que cada dependência crítica do seu projeto suporta Fabric. Esse é o passo mais subestimado da migração — vale dedicar uma tarde inteira a ele.

Migração em projeto Expo (managed e bare)

Para projetos Expo, o processo é radicalmente mais simples graças ao prebuild e ao autolinking, que abstraem boa parte da configuração nativa.

Passo 1: Atualizar o SDK

npx expo install expo@^54.0.0
npx expo install --fix

O comando --fix alinha todas as bibliotecas expo-* e dependências conhecidas com a versão do SDK. Honestamente, esse comando sozinho já economiza horas de "por que esse pacote tá com versão errada?".

Passo 2: Habilitar a Nova Arquitetura no app.json

{
  "expo": {
    "name": "MeuApp",
    "newArchEnabled": true,
    "ios": { "newArchEnabled": true },
    "android": { "newArchEnabled": true }
  }
}

Em projetos novos do SDK 53+, esse flag já vem como true por padrão. Em projetos antigos, remova qualquer linha "newArchEnabled": false.

Passo 3: Regenerar a pasta nativa

npx expo prebuild --clean

O --clean apaga as pastas android/ e ios/ e regenera tudo a partir do app.json. Cuidado: se você tem código nativo customizado, mova-o para um config plugin antes de rodar este comando — caso contrário ele será sobrescrito (e sim, eu já perdi código assim).

Passo 4: Build e validação

npx expo run:ios --device
npx expo run:android

Procure por warnings de "Module X not found" ou "Bridge fallback used". Esses logs indicam que algum pacote ainda está sendo carregado pelo modo de interoperabilidade. Funciona, mas não dá ganho de performance.

Migração em projeto bare (CLI puro)

Em projetos sem Expo, a migração toca diretamente nos arquivos de build de cada plataforma. Mais trabalho, mais controle.

Android: gradle.properties

# android/gradle.properties
newArchEnabled=true
hermesEnabled=true

Em seguida, limpe o cache nativo:

cd android && ./gradlew clean && cd ..

iOS: Podfile

# ios/Podfile
ENV['RCT_NEW_ARCH_ENABLED'] = '1'

use_react_native!(
  :path => config[:reactNativePath],
  :hermes_enabled => true,
  :fabric_enabled => true
)

Reinstale os pods com a flag certa:

cd ios
RCT_NEW_ARCH_ENABLED=1 pod install --repo-update
cd ..

Limpeza obrigatória

Builds incrementais quase sempre dão problema na primeira vez (regra não escrita do Xcode). Antes do primeiro run, apague tudo:

watchman watch-del-all
rm -rf node_modules && npm install
rm -rf ios/build android/app/build
rm -rf ios/Pods ios/Podfile.lock

Convertendo um Native Module em TurboModule

Se você mantém um módulo nativo customizado com a API NativeModules, ele precisa ser reescrito como TurboModule. O processo gira em torno do Codegen e de uma spec em TypeScript.

Passo 1: Criar a spec TypeScript

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

export interface Spec extends TurboModule {
  getBatteryLevel(): Promise<number>;
  isCharging(): boolean;
  addListener(eventName: string): void;
  removeListeners(count: number): void;
}

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

Passo 2: Configurar o Codegen no package.json

{
  "codegenConfig": {
    "name": "AppSpec",
    "type": "modules",
    "jsSrcsDir": "src/specs",
    "android": {
      "javaPackageName": "com.meuapp.specs"
    }
  }
}

Passo 3: Implementação Android (Kotlin)

package com.meuapp.battery

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.Promise
import com.meuapp.specs.NativeBatteryModuleSpec

class BatteryModule(context: ReactApplicationContext)
  : NativeBatteryModuleSpec(context) {

  override fun getName() = "BatteryModule"

  override fun getBatteryLevel(promise: Promise) {
    val batteryManager = reactApplicationContext
      .getSystemService(Context.BATTERY_SERVICE) as BatteryManager
    val level = batteryManager
      .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
    promise.resolve(level / 100.0)
  }

  override fun isCharging(): Boolean { /* ... */ }
}

Passo 4: Implementação iOS (Objective-C++)

// BatteryModule.mm
#import "BatteryModule.h"
#import <UIKit/UIKit.h>

@implementation BatteryModule

RCT_EXPORT_MODULE()

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

- (void)getBatteryLevel:(RCTPromiseResolveBlock)resolve
                 reject:(RCTPromiseRejectBlock)reject {
  UIDevice *device = UIDevice.currentDevice;
  device.batteryMonitoringEnabled = YES;
  resolve(@(device.batteryLevel));
}

@end

Depois dessa estrutura, rode npx react-native codegen para gerar os bindings em C++ e os adaptadores nativos. O JavaScript importa a spec, e o Codegen garante que assinatura e implementação batem em compile time. Adeus, erros de runtime por typo de método.

Convertendo um Native Component em Fabric Component

Para Views nativas customizadas, o caminho é parecido. A spec descreve as props e eventos do componente:

// src/specs/MyMapViewNativeComponent.ts
import type { ViewProps } from 'react-native';
import type { Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from
  'react-native/Libraries/Utilities/codegenNativeComponent';

interface NativeProps extends ViewProps {
  zoom: Float;
  region: { latitude: Float; longitude: Float };
  pinCount: Int32;
}

export default codegenNativeComponent<NativeProps>('MyMapView');

O Codegen vai gerar a interface MyMapViewProps em C++ e os adaptadores do lado nativo. A implementação em iOS herda de RCTViewComponentView, e em Android de SimpleViewManager<ReactViewGroup> com RNCMyMapViewManagerInterface.

Camada de interoperabilidade: o caminho de fuga

Nem toda biblioteca foi reescrita ainda. Para evitar bloqueio, o React Native fornece uma camada de interoperabilidade que faz módulos antigos rodarem dentro do Fabric:

  • Legacy Native Module Interop: ativada por padrão. Permite que módulos baseados em NativeModules continuem funcionando, mas sem o ganho de performance do JSI.
  • Legacy View Interop: permite que Native Components antigos sejam embrulhados pelo renderizador Fabric. Funcional, mas perde renderização concorrente.

Use a camada de interop como ponte temporária, não como solução permanente. Documente cada biblioteca não migrada com um item no backlog para acompanhamento — senão, daqui a seis meses, ninguém lembra mais do que faltou.

Validação e rollout em produção

Equipes que migraram com sucesso (Shopify, Bluesky, Discord, Coinbase) seguem um padrão comum: rollout percentual com observabilidade. Não tem segredo, tem disciplina.

Métricas a monitorar

  • Cold start (Time to Interactive) — esperado: queda de 30–45%.
  • Crash rate — qualquer aumento > 0,1% versus baseline já é red flag.
  • ANR (Application Not Responding) no Android — atenção especial à thread principal.
  • Frame rate em telas com listas e animações — meta de 60fps consistente.
  • Memória — esperado: queda de 20–30% em apps complexos.

Estratégia de ramp-up

O Shopify documentou seu rollout do Shopify Mobile partindo de 8% → 25% → 50% → 75% → 100%, com pelo menos 3–5 dias de observação entre os incrementos. Para apps menores, um ciclo mais curto (10% → 50% → 100%) costuma ser suficiente, desde que cada estágio tenha confirmação de métricas estáveis.

Em apps Expo, use EAS Update com channels separados para canary e produção. Em projetos bare, distribua via Firebase App Distribution ou TestFlight em fases.

Erros comuns durante a migração

1. "Cannot read property of undefined" em Native Modules antigos

Geralmente significa que o módulo não foi registrado pelo autolinking e a camada de interop não conseguiu identificá-lo. Confirme se a biblioteca tem react-native.config.js ou se está listada no autolinking do projeto.

2. Build iOS quebrando com erros do Boost

cd ios
pod deintegrate
rm -rf Pods Podfile.lock build
RCT_NEW_ARCH_ENABLED=1 pod install --repo-update

Esse padrão resolve a maioria dos erros relacionados a headers C++ não encontrados. Já salvou minha noite umas três vezes.

3. Animações Reanimated 3 quebrando após upgrade

Reanimated 4 mudou o babel plugin de 'react-native-reanimated/plugin' para 'react-native-worklets/plugin'. Atualize o babel.config.js e instale o pacote react-native-worklets:

npx expo install react-native-worklets react-native-reanimated

4. FlatList com scroll travado

O Fabric expõe diferenças no virtualizador antigo. A solução recomendada para listas grandes em 2026 é migrar para FlashList v2 ou LegendList, ambas otimizadas para o novo renderizador.

5. Tela branca após splash em iOS

Quase sempre é causado pelo SafeAreaView legado, que foi depreciado no React Native 0.81. Substitua por react-native-safe-area-context:

import { SafeAreaView } from 'react-native-safe-area-context';

Boas práticas pós-migração

  • Habilite o React Compiler. Em apps na Nova Arquitetura, o React Compiler do React 19 elimina a maior parte dos useMemo e useCallback manuais sem prejudicar performance.
  • Use Reanimated 4 com CSS Animations. A nova API declarativa animationName + keyframes substitui boa parte dos worklets para casos simples.
  • Adote FlashList v2 ou LegendList. Ambas usam recycleViews nativo do Fabric e ganham desempenho que o FlatList do core não consegue alcançar.
  • Monitore com Expo Atlas. Estável desde o SDK 53, ele expõe o tamanho do bundle JS e ajuda a identificar dependências pesadas que viraram redundantes após a migração.
  • Remova polyfills antigos. Vários workarounds de Bridge (debounce de batch, InteractionManager, requestAnimationFrame manuais) deixam de fazer sentido com JSI síncrono.

Quando NÃO migrar agora

Há cenários legítimos para adiar:

  • Você depende de uma biblioteca crítica sem versão Fabric e sem alternativa viável (raro em 2026, mas acontece).
  • O app está congelado em manutenção mínima e será descontinuado em até 6 meses.
  • Você está em meio a outro grande refactor (ex.: migração TypeScript) e fazer dois ao mesmo tempo só aumenta risco sem benefício.

Mesmo nesses casos, a recomendação é congelar a versão em React Native 0.81 + Expo SDK 54, onde o opt-out ainda é possível, e planejar a migração para o próximo ciclo. Não fique para trás demais.

FAQ — Perguntas frequentes sobre a migração

A Nova Arquitetura é obrigatória em 2026?

Sim, na prática. React Native 0.82 remove o Bridge completamente, e Expo SDK 55 (lançamento em 2026) só roda na Nova Arquitetura. SDK 54 é o último que aceita opt-out, e qualquer app que pretenda receber atualizações de segurança e novas bibliotecas precisa migrar.

Posso usar a Nova Arquitetura sem reescrever todo o código JavaScript?

Sim. A maior parte do código JS continua funcionando sem mudanças. As alterações concentram-se em (1) flags de build, (2) substituição de bibliotecas que dependiam do Bridge e (3) reescrita de Native Modules e Native Components customizados. A camada de interoperabilidade ainda permite rodar módulos antigos em modo de fallback.

Quanto tempo dura uma migração típica?

Para apps Expo managed, de 1 a 5 dias. Para apps bare com poucos módulos nativos, 1 a 3 semanas. Para apps grandes com módulos customizados próprios, 4 a 8 semanas — e a maior parte do tempo é gasta em validação cross-device, não em codificação.

Vale a pena migrar um app Expo antigo direto para o SDK 54 ou ir incrementalmente?

Para projetos com até 2 SDK versions de defasagem, ir direto é viável e recomendado. Para defasagens maiores (SDK 49 ou inferior), faça saltos de 2 SDKs por vez (ex.: 49 → 51 → 53 → 54), validando o app a cada salto. Isso isola a origem de qualquer regressão e poupa muita dor de cabeça.

O que acontece com bibliotecas que ainda dependem de NativeModules?

Continuam funcionando via camada de interop, mas perdem o ganho de performance do JSI. Em 2026, a maior parte do ecossistema (React Navigation 7+, Reanimated 4, FlashList v2, Skia, Gesture Handler 2.16+, Vision Camera 4+, Expo modules) já foi reescrita para Fabric. Bibliotecas órfãs sem manutenção devem ser substituídas por alternativas mantidas — encare isso como uma boa oportunidade para limpar dependências.

JSI substitui o Bridge totalmente ou eles coexistem?

Na Nova Arquitetura habilitada, o Bridge não existe mais como rota de comunicação. JSI é o único mecanismo. A camada de interop simula uma API antiga sobre o JSI para compatibilidade, mas a transferência real de dados entre JS e nativo é sempre via JSI.

Conclusão

Migrar para a Nova Arquitetura em 2026 é menos uma decisão e mais uma execução planejada. As ferramentas estão maduras: o autolinking transitivo do SDK 54 reduziu o trabalho de configuração, o Codegen automatiza os bindings, o ecossistema está 90% compatível e os ganhos de performance (40% em cold start, 30% em memória) são consistentes em todos os casos documentados.

O caminho mais seguro? Comece por um app secundário ou um fork de produção, valide todas as suas dependências críticas, execute um rollout em fases com observabilidade ativa e só então remova a interoperabilidade legada. Apps que executam essa migração agora ganham seis meses de vantagem sobre quem vai correr quando o React Native 0.82 for lançado e o Bridge desaparecer de vez.

Sobre o Autor Editorial Team

Our team of expert writers and editors.