# Migrating to the React Native New Architecture: A Practical Guide

> Step-by-step guide to migrating your React Native app to the New Architecture — Fabric, JSI, and TurboModules — without breaking production.

- **Published:** 2025-05-01
- **Author:** Clixo
- **Reading time:** 5 min read
- **Tags:** react-native, new-architecture, turbomodules, performance, mobile
- **Canonical URL:** https://clixo.sh/blog/react-native-new-architecture-migration-guide

Your React Native app works fine today. But starting with React Native 0.76, the New Architecture became the default, and from 0.82 the old bridge is officially deprecated with no further bugfixes. If you are still on the legacy bridge, you are now accumulating technical debt that will compound with every future upgrade.

This guide walks through what the New Architecture actually changes, what breaks during migration, and how to sequence the work so you ship updates without regressions.

## What the React Native New Architecture Actually Changes

The legacy bridge serialized every JavaScript-to-native call to JSON, passed it across an async bridge, then deserialized it on the native side. That round-trip added latency on every interaction and made synchronous calls impossible.

The New Architecture replaces this with three components:

- **JSI (JavaScript Interface)**: a C++ layer that lets JavaScript hold direct references to native objects. No serialization, no async round-trip for synchronous operations.
- **Fabric**: the new renderer, built on JSI, that allows the native UI layer and the JS thread to share memory and synchronize layout without passing messages.
- **TurboModules**: lazy-loaded native modules accessed synchronously via JSI instead of the old bridge. A module is only initialized the first time JavaScript touches it.

Teams that have published migration data report cold start improvements in the range of 30-40%, and JS-to-native call latency reductions of an order of magnitude on operations that previously required async bridge calls.

## Assessing Your Migration Surface Area

Before writing a line of code, audit your dependency list. The migration gate is not your own code — it is your third-party native modules.

Run this in your project root:

```bash
npx react-native info
```

Then cross-reference every package with a native dependency against the [React Native Directory](https://reactnative.directory) to confirm New Architecture support. Any package that is not compatible blocks your migration until the package is updated or replaced.

Pay special attention to:

- Custom native modules your team wrote using the old `@ReactMethod` / `RCT_EXPORT_METHOD` pattern
- Packages that rely on `RCTBridge` directly
- Any package wrapping a third-party SDK that the vendor has not yet updated

### Categorize Your Native Modules

Sort every native module into one of three buckets:

1. **Already compatible** — supports the New Architecture, no action needed
2. **Needs interop layer** — not compatible yet, but the built-in interop layer can run it temporarily while you migrate
3. **Must replace or rewrite** — incompatible and the interop layer cannot bridge it

The interop layer ships with React Native 0.74+ and exists specifically to let you turn on the New Architecture app-wide while leaving a handful of legacy modules running temporarily. It is not a permanent solution.

```mermaid
flowchart TD
  A[Audit Native Modules] --> B{New Architecture Support?}
  B -->|Already compatible| C[No Action Needed]
  B -->|Interop layer works| D[Use Interop Layer Temporarily]
  B -->|Incompatible| E[Replace or Rewrite Module]
  C --> F["Enable newArchEnabled=true"]
  D --> F
  E --> G[Migrate to TurboModule Spec]
  G --> F
  F --> H[Test on Android and iOS]
  H --> I[Profile and Verify Performance]
```

## Enabling the New Architecture

### On Android

In `android/gradle.properties`, set:

```
newArchEnabled=true
```

### On iOS

In `ios/Podfile`, the New Architecture is enabled by default from React Native 0.76+. If you are on an older version, add:

```ruby
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
```

Then run `pod install`.

## Migrating Your Own Native Modules to TurboModules

If you maintain custom native modules, you need to rewrite them using the TurboModule spec pattern.

The high-level steps:

1. **Write a TypeScript spec file** that defines the module's interface. CodeGen reads this file to generate the C++ bindings automatically.
2. **Implement the native side** in Swift or Kotlin, conforming to the generated protocol/interface.
3. **Register the module** using the new `TurboModuleManagerDelegate` pattern on iOS and `ReactPackage` on Android.
4. **Delete the old bridge registration** — `RCT_EXPORT_MODULE()` and friends.

The Expo Modules API is a practical alternative if you want to skip most of this boilerplate. It sits on top of TurboModules and lets you write Swift and Kotlin directly without touching Objective-C or the codegen configuration manually.

## Testing the Migration

Do not migrate production in a single PR. The recommended approach:

- Enable the New Architecture in a dedicated branch or a feature-flagged build variant.
- Run your full test suite. Pay special attention to anything that touches native modules, navigation, or gesture handling.
- Profile the migrated build using the Flipper Performance panel or the built-in Systrace tool. Verify that JavaScript thread and UI thread frame drops are not regressing.
- Test on a mid-tier Android device, not just a developer MacBook running a simulator. The performance characteristics differ significantly.

## Common Breakage Patterns

**Synchronous native calls that were "accidentally working"**: Some teams relied on the fact that certain bridge calls happened to resolve quickly and treated them as synchronous. Fabric makes the threading model stricter and these assumptions break.

**Event emitters**: The event emitter API changed. Modules that emit events to JavaScript need to use `EventEmitter` from the new spec pattern.

**Layout animations**: Some layout animation patterns that worked with the legacy renderer behave differently under Fabric. Test every screen that uses `LayoutAnimation`.

**React Navigation**: Make sure you are on React Navigation 6.x or later, which has explicit New Architecture support.

## What You Gain After Migration

Once the migration is complete:

- Synchronous access to native APIs from JavaScript where appropriate
- Faster cold starts from lazy TurboModule initialization
- Eliminated serialization overhead on all native calls
- Access to concurrent rendering features in React 18

The old bridge will not receive security patches or compatibility updates for new React Native versions going forward. The longer you wait, the harder the migration becomes as the API surface drifts further apart.

If your team is carrying multiple custom native modules or a large dependency graph, the migration is a multi-sprint project, not a one-afternoon job. [Reach out to Clixo](https://clixo.sh/#contact) if you need a team to scope and execute the migration alongside your engineers.

---

Clixo · 1141 W Bryn Mawr Ave, Itasca, IL 60143, US · [hello@clixo.sh](mailto:hello@clixo.sh)
[Start a build](https://clixo.sh/#contact) · [All services](https://clixo.sh/services) · [Agent guide (llms.txt)](https://clixo.sh/llms.txt)
