Guide

Debugging React Native's New Architecture: What Breaks and How to Find It

The New Architecture is now the default. It's also causing real issues — performance regressions, layout bugs, animation stuttering, and library crashes. Here's how to systematically find and fix them.

What happened

React Native's New Architecture — Fabric renderer, TurboModules, and JSI — replaced the old bridge-based system. As of React Native 0.82 and Expo SDK 55, you can no longer disable it. The old architecture is frozen: no features, no bugfixes.

The migration has been years in the making, and the performance improvements are real — synchronous native calls, no JSON serialization overhead, concurrent React support. But the transition has been rough. The 2025 State of React Native survey found that 54% of developers cite better debugging as their top request, and the New Architecture remains a pain point even at ~50% adoption.

The issues are real and well-documented. Shopify's migration of their two largest apps saw stability drops, ANR spikes, and 20% load time increases on complex components. Reanimated has open issues with severe animation degradation on Android. React-native-screens has layout desync bugs in Fabric. The new React Native DevTools are improving but still maturing.

If you've migrated and things are broken — or you're about to migrate and want to know what to watch for — this guide covers the four most common categories of post-migration issues and how to debug each one.

1. Performance regressions

The most common surprise: your app gets slower after migration. Components that rendered in milliseconds now take hundreds. Lists stutter. Screen transitions lag.

This usually isn't the New Architecture being slower — it's the New Architecture exposing inefficiencies that the old bridge masked. The old architecture's asynchronous batching hid expensive renders behind UI thread decoupling. Fabric renders synchronously for user interactions, which means expensive components now directly block the UI.

How to find it

React Native DevTools Performance panel (0.83+). React Native 0.83 introduced a Performance panel modeled after Chrome's. Record a trace, then inspect the Scheduler tracks — Blocking, Transition, Suspense, and Idle. Look for render phases that exceed 16ms (the budget for 60fps). Pay attention to the "Remaining Effects" phase: if a re-render triggers a long-running useEffect, the UI won't update until that effect finishes.

React Profiler. Use the Components tab in DevTools to profile renders. Sort by render duration to find your most expensive components. The "Why did this render?" feature tells you whether it was a props change, state update, or parent re-render.

Runtime context tools. Tools like Limelight can profile renders automatically and correlate them with the state changes and network requests that triggered them. This is especially useful for identifying cascade effects — where one slow component triggers a chain of re-renders across the tree.

Common culprits

  • Inline function props — arrow functions in JSX create new references every render, defeating React.memo. Wrap in useCallback.
  • Expensive computations in render — date parsing, filtering, sorting that was "fast enough" with async bridge batching is now a visible bottleneck. Move to useMemo.
  • FlatList without getItemLayout — Fabric's synchronous rendering makes unmeasured list items more expensive. Always provide getItemLayout or switch to FlashList / Legend List.
  • Console.log in production builds — even third-party libraries may have console calls. Use babel-plugin-transform-remove-console in release builds.

What the debugging output looks like

When you profile a performance regression, you're looking for the causal chain from trigger to slow render:

Trigger: User typed in SearchInput
State update: searchQuery → "react native new arch"
Re-renders:
  SearchInput (0.4ms) ✓
  SearchResults (2.1ms) ✓
  DashboardStats (148ms) SLOW
    ↳ cause: parent re-render (not props/state)
    ↳ expensive: filterTransactions() called in render
  ActivityFeed (89ms) SLOW
    ↳ cause: unstable onRefresh prop (new ref every render)

In this example, typing in a search input re-renders the entire screen because the parent doesn't isolate state. DashboardStats and ActivityFeed are expensive and shouldn't be re-rendering at all. The fixes: extract SearchInput state into its own component, memoize filterTransactions, and wrap onRefresh in useCallback.

2. Layout desyncs

Fabric maintains a shadow tree — an off-screen representation of your UI that drives layout calculations via Yoga. The shadow tree and the actual native views should always agree. When they don't, you get layout desyncs: views jumping to incorrect heights on re-render, modals resizing unexpectedly, or touch targets not matching visual positions.

This is a known category of issues, particularly with navigation libraries. React-native-screens has documented cases where presenting a modal triggers rapid updateBounds calls that cause the shadow tree to go out of sync, resulting in incorrect heights on subsequent re-renders.

How to find it

Isolate the trigger. Layout desyncs typically surface on re-render, not initial render. If the first render looks correct but subsequent renders break layout, you're likely hitting a shadow tree desync. Reduce your screen to the minimal reproduction — strip components until you find which one triggers the jump.

Check Animated components. Views using React Native's Animated components (Animated.View, TouchableOpacity) have been observed to cause double-rendering on load in the New Architecture, which can trigger layout recalculations. If removing an Animated wrapper fixes the layout, you've found the source.

Watch for native-side layout updates. Libraries that call updateState directly on shadow nodes from native code (outside a React render cycle) can desync the tree. This is a common pattern in navigation libraries that adjust view bounds when presenting or dismissing screens. Check GitHub issues for your specific library + "New Architecture."

Workarounds

  • Pin to the latest version of react-native-screens and react-navigation — fixes ship frequently
  • Use collapsable={false} on views that need stable layout to prevent Fabric from optimizing them away
  • If a library is manipulating native views outside React's render cycle, check if there's an updated version that uses JS-driven layout instead
  • Report reproductions upstream — the Fabric team is actively fixing desync sources

3. Animation stuttering

Reanimated 4 shipped with CSS animations and transitions support, and Worklets are now a standalone package. But there are known performance regressions on Android when using Reanimated with the New Architecture enabled. Animations that ran smoothly on the old architecture now stutter and lag — in some cases severely enough to make the app feel unusable.

This affects Reanimated versions from 3.16 through 4.x. The issue is specific to Android; iOS performance is generally unaffected.

How to confirm it's Reanimated + New Architecture

  • Platform check — if the stuttering only happens on Android, it's likely this issue
  • Simple animation test — create a minimal screen with one Reanimated animation triggered by a Pressable. If it stutters on Android with New Architecture but is smooth on iOS, you've confirmed it
  • Check the GitHub issue — react-native-reanimated issue #7435 tracks this. Pin a comment or subscribe for updates

What to do in the meantime

If you can't wait for a fix, consider whether the affected animations can use React Native's built-in Animated API or CSS-based animations (available in Reanimated 4) instead of worklet-driven animations. For screen transitions, check if your navigation library offers non-Reanimated animation options.

For critical paths, profile with the Performance panel to determine exactly how much time is being lost. Some teams have found that the stuttering is tolerable in non-critical animations but requires workarounds for hero transitions and gesture-driven interactions.

4. Library incompatibility

The old bridge and the New Architecture are fundamentally different in how they communicate between JavaScript and native code. Libraries built on the old bridge — using NativeModules and the legacy renderer — may crash, behave incorrectly, or silently fail on the New Architecture.

How to audit your dependencies

React Native Directory. The community maintains compatibility status for most popular libraries at reactnative.directory. Filter by "New Architecture" support to see which of your dependencies are verified, untested, or known incompatible.

expo-doctor. Run npx expo-doctor to automatically check your dependencies against the React Native Directory data. It flags unmaintained packages and those that are incompatible or untested with the New Architecture.

Runtime crash isolation. If your app crashes after migration and you're not sure which library is responsible, comment out providers and native modules one by one in your App component until the crash stops. This is Shopify's recommended approach — brute-force but reliable.

Common patterns

  • UIManager access errors — libraries that use UIManager directly will break on Fabric. Look for "UIManager is not defined" or similar errors
  • Native module initialization crashes — some native modules that initialized on the main thread without issue on the old architecture can cause deadlocks or ANRs on the New Architecture
  • Shadow tree manipulation — libraries that manipulate React Native views from native UIManagers (swapping views, adjusting frames) can cause crashes or UI desyncs under Fabric

What to do with incompatible libraries

  • Check for maintained forks that support the New Architecture
  • Look for drop-in replacements — many popular libraries have New Architecture-ready alternatives
  • If the library is critical and unmaintained, consider wrapping or rebuilding the module using TurboModules or the Expo Modules API (which supports the New Architecture by default)
  • Contribute fixes upstream — the maintainer may not have tested against the New Architecture yet

A debugging strategy for migration

If you're in the middle of a migration (or just landed on the New Architecture via an SDK upgrade), here's a systematic approach:

1. Audit dependencies first

Run npx expo-doctor and check React Native Directory before you start debugging runtime issues. There's no point profiling a performance regression if the root cause is an incompatible library.

2. Establish a pre-migration baseline

If you haven't migrated yet, profile your critical screens on the old architecture first. Record render times, interaction latency, and crash-free session rates. Without a baseline, you won't know whether a post-migration issue is new or pre-existing.

3. Enable Fabric in dev, test in production gradually

Get the New Architecture running in your development environment first. Fix the obvious crashes and layout issues. Then use app store gradual rollout features (1% → 5% → 25% → 100%) to catch issues that only appear at scale or on specific devices.

4. Categorize issues before fixing

Not all post-migration bugs have the same root cause. Before you start optimizing, determine which category you're in: performance regression (profile it), layout desync (isolate the trigger), animation stuttering (platform-check it), or library incompatibility (audit it). The fix depends entirely on the category.

5. Use runtime context to trace cause and effect

The hardest post-migration bugs are the ones where something is "just slower" or "sometimes breaks" without an obvious cause. This is where runtime event correlation helps — linking a user interaction to the state update it triggered, to the components that re-rendered, to the time each render took. Tools like the Performance panel, React Profiler, or Limelight's correlation engine can surface these chains automatically.

FAQ

Only on SDK 54 and earlier. SDK 55 uses React Native 0.83, which always runs on the New Architecture — there's no opt-out. If you're stuck on a blocking issue, staying on SDK 54 temporarily is an option, but the old architecture is frozen (no new features or bugfixes).
React Native Directory tracks compatibility status for most popular libraries. You can also run npx expo-doctor to check your dependencies automatically. Libraries built with the Expo Modules API support the New Architecture by default.
In synthetic benchmarks, yes — especially for text rendering and component mounting. In real apps, it depends. Shopify saw 20% load time increases on some complex components after migrating, not because the architecture is slower, but because it exposed existing inefficiencies that were previously hidden. You may need to optimize code that "worked fine" before.
Incrementally. Enable Fabric in development first to surface issues early. Migrate one native module to TurboModules at a time. Use phased rollouts via app store gradual release features. Shopify's advice: "fix forward when possible — avoid rollbacks to maintain momentum."

Debug in real time. Ship with confidence.