How to upgrade React Native without breaking your builds

A practical order of work for Expo and React Native CLI projects: what to check before you touch versions, the official commands for each workflow, and the failures that eat most upgrade time.

1. Know where you start

Write down the React Native, React and Expo SDK versions you actually have installed, not just the ranges in package.json. How to check your React Native version shows the commands. Then decide the target. For Expo projects the target is an SDK; for bare projects it is a React Native release.

Paste your package.json into the upgrade checker to see which dependencies the target's official data says must move, which ones need a closer look, and which ones no source covers.

2. Prepare the branch

  • Start from a clean, building main branch. An upgrade on top of an already broken build hides the real cause.
  • Commit the lockfile before and after. The diff of package-lock.json, yarn.lock or pnpm-lock.yaml is the record of what really changed.
  • Check your Node.js version against the target. Each React Native release declares a Node engine range on npm, and Expo lists a minimum Node version per SDK.
  • List native customizations: patch-package patches, edits in ios/ and android/, config plugins. Each one needs a re-check after the upgrade.

3a. Expo projects

Expo recommends going one SDK version at a time. For each step:

# 1. move expo and let Expo align every SDK package
npx expo install expo@^58.0.0 --fix

# 2. find what is still wrong
npx expo-doctor

# 3. Continuous Native Generation: delete generated native folders
rm -rf ios android
# otherwise, with your own native folders:
npx pod-install

Read the release notes for each SDK you pass through. They list removed packages, renamed APIs and config changes that no version check can catch. The Expo SDK compatibility table shows which React Native and React each SDK brings with it.

3b. React Native CLI projects

Bare projects upgrade the JavaScript dependency and the native template files separately.

# 1. bump react-native and react to the template versions for the target
npm install react-native@0.88.1 react@19.3.0

# 2. apply the native template diff (Gradle files, Podfile, AppDelegate, MainApplication)
#    https://react-native-community.github.io/upgrade-helper/?from=0.81.5&to=0.88.1

# 3. reinstall pods and check the environment
cd ios && pod install && cd ..
npx @react-native-community/cli doctor

The Upgrade Helper shows the diff between the app templates of two versions. Apply it by hand; most of the work is in android/build.gradle, android/gradle/wrapper/gradle-wrapper.properties, ios/Podfile and the native app entry files. Then upgrade each native library to a version that declares support for the new React Native.

4. The New Architecture cut-over

React Native 0.82 supports only the New Architecture. If you are coming from 0.81 or earlier with the old architecture enabled, every native library you use must support the New Architecture before you cross that line. Check each one's release notes or React Native Directory, and plan this as its own step: first enable the New Architecture on your current version and fix what breaks, then upgrade.

5. Verify like a release

  • Clean builds: clear Metro (npx expo start --clear or npx react-native start --reset-cache), and Gradle and Xcode build folders.
  • Release builds on both platforms. Debug builds skip minification and other release-only steps, so some failures only appear there.
  • Run your test suite and click through the flows that use native modules: camera, maps, payments, push notifications, deep links.

Common failure scenarios

Two copies of React

Symptoms: "Invalid hook call" or hooks behaving strangely after the bump. Run npm ls react (or yarn why react). Every package should resolve to one React version, the one your React Native version expects.

CocoaPods can't resolve versions

After a native library upgrade, pod install can fail because Podfile.lock pins old versions. pod install --repo-update refreshes the specs. Only delete Podfile.lock if you understand which pods will move.

Gradle, AGP or JDK mismatch

Android builds fail early with version errors when gradle-wrapper.properties, the Android Gradle Plugin, or your JDK don't match what the new template expects. Copy the versions from the Upgrade Helper diff instead of guessing, and use the JDK the React Native environment setup docs name for your version.

Reanimated Babel plugin

Reanimated 4 moved its Babel plugin to react-native-worklets. In bare projects, change the plugin in babel.config.js:

plugins: [
-  'react-native-reanimated/plugin',
+  'react-native-worklets/plugin',
],

Expo projects using babel-preset-expo do not list the plugin themselves. See the Reanimated 3.x to 4.x migration guide.

Patches that no longer apply

patch-package warns when a patch fails against the new version. A silently skipped patch brings back the bug it fixed. Check each patch: drop it if upstream fixed the issue, or regenerate it.

Stale caches look like upgrade bugs

Metro, Watchman, Gradle and Xcode DerivedData can hold old artifacts. Clear them before you debug a strange error after the version change.

FAQ

Should I skip versions to save time?

For Expo, the docs recommend one SDK at a time so you can pinpoint breakages. For bare projects the Upgrade Helper can diff any two versions, but a big jump means a big diff and many libraries to move at once. Smaller steps are easier to debug.

How long does a React Native upgrade take?

It depends on the number of native libraries, custom native code and how far you jump, not on the size of your JavaScript. The upgrade checker gives a rough complexity score from these factors; treat it as a heuristic.

Do I need to upgrade every dependency?

No. Upgrade what the target requires: React, packages Expo pins for the SDK, and native libraries whose declared React Native range excludes the target. Leave the rest for a separate change.

Official documentation

Stuck on a build that won't come back after an upgrade? I fix React Native and Expo upgrades, native dependency conflicts, and iOS and Android build failures.

Get upgrade help