Upgrading React Native is rarely blocked by a single big change. Most failed upgrades come from small mismatches: a library that quietly depends on an older Android setting, a navigation package that lags one release behind, an iOS build script that was never documented, or a test suite that does not cover startup flows. This guide gives you a reusable checklist for minor and major React Native upgrades, with practical steps for planning, execution, validation, and rollback. Keep it bookmarked and use it before each release cycle, especially when your app depends on Expo, native modules, custom build logic, or a larger set of third-party packages.
Overview
This article gives you a safe, repeatable process to upgrade React Native without turning a version bump into a week of build failures. The goal is not to upgrade as fast as possible. The goal is to upgrade with control.
A good react native migration guide starts with one assumption: the JavaScript version number is only part of the upgrade. In a real app, you are also upgrading some combination of React, Hermes, Gradle, Android SDK settings, Xcode project files, CocoaPods dependencies, Expo SDK alignment, navigation libraries, testing tools, and native modules.
That is why the safest way to upgrade React Native is to treat it like a small engineering project with a checklist:
- Define scope before changing versions.
- Confirm compatibility across the full dependency chain.
- Upgrade in a controlled branch.
- Validate native builds, app startup, navigation, authentication, analytics, notifications, and release output.
- Keep rollback simple.
As a rule of thumb, a minor release often fits an incremental update path, while a major release should be handled as a broader migration. Even when release notes make an upgrade look small, your app may still carry old assumptions from previous versions.
Before you begin, classify your project into one of these groups:
- Expo managed workflow: your upgrade path is shaped by Expo SDK support windows and package alignment.
- React Native CLI app: you control native projects directly and need to review Android and iOS changes more closely.
- Hybrid or heavily customized app: native modules, custom Gradle settings, build scripts, or private SDKs increase upgrade risk and testing needs.
If you need help mapping version compatibility across your stack, keep a reference list nearby and compare React Native, React, Hermes, Expo, and navigation packages together. A useful companion read is React Native Version Compatibility Matrix: Expo, React, Hermes, and Navigation.
Checklist by scenario
Use the scenario that matches your app, then run the shared validation checklist later in this article. The point is to reduce guesswork before you update react native version in package.json or trigger native dependency installs.
Scenario 1: Minor React Native upgrade with limited native customization
This is the lowest-risk path. You are likely moving one supported release forward, your app uses mainstream libraries, and native projects are close to standard templates.
- Create an upgrade branch. Do not mix the version bump with unrelated refactors, linting changes, or design work.
- Record the current baseline. Save the current app version, commit SHA, release build status, and test results.
- Review official upgrade notes and breaking changes. Focus on installation changes, deprecations, Android/iOS project updates, and runtime behavior.
- Check package compatibility. Review navigation, gesture handling, animation libraries, storage, authentication, push notifications, analytics, and testing packages.
- Update core versions together where needed. React Native often moves with expected versions of React and related tooling.
- Reinstall dependencies cleanly. Remove node_modules and lockfile only if your team accepts that workflow; otherwise prefer a controlled package manager update. On iOS, refresh pods after JavaScript dependencies are aligned.
- Build Android debug and iOS debug first. Fix compile errors before trying release builds.
- Run smoke tests on at least one real iOS device and one real Android device. Simulator-only validation misses camera, notifications, performance, and some permission edge cases.
- Run release builds before merging. A debug build passing does not guarantee production signing, ProGuard or R8 behavior, or archive success.
Scenario 2: Major React Native upgrade
This is where a structured react native upgrade checklist matters most. Major releases can shift defaults, remove deprecated APIs, change template files, or tighten native toolchain requirements.
- Plan the upgrade window. Avoid bundling a major framework upgrade with a high-risk feature launch.
- Audit your dependencies by risk. Group them into: core runtime, navigation and UI, native integrations, build tooling, testing, and release automation.
- Identify blockers early. Any unmaintained native module, private SDK, or forked dependency should be reviewed before changing the framework version.
- Compare your native projects to a fresh project template. Major versions sometimes expect changes in AppDelegate, MainApplication, Gradle config, Android manifest settings, or build scripts.
- Upgrade one layer at a time. Start with the framework and required peer dependencies, then fix build system issues, then update dependent libraries, then validate runtime behavior.
- Test old assumptions. Re-check startup timing, deep linking, navigation transitions, keyboard handling, backgrounding, splash behavior, and app state listeners.
- Schedule extra QA for production-only paths. Login persistence, push notifications, OTA or bundle delivery logic, release signing, and analytics initialization often break outside normal local development.
- Prepare a rollback point. Tag the last known stable release and keep a revert plan ready for your mobile CI/CD pipeline.
Scenario 3: Expo app upgrade
For Expo-based apps, the framework upgrade is usually shaped by the SDK cycle. That does not make the process automatic; it changes where the risk sits.
- Confirm the target Expo SDK first. Then verify the corresponding React Native and package expectations.
- Use Expo-approved package alignment where possible. This reduces version drift across core packages.
- Review config plugin and native capability changes. Notifications, camera, location, splash screen behavior, and build properties deserve extra attention.
- Validate EAS or your chosen build pipeline after dependency changes. Build settings can fail even when local Metro runs correctly.
- If you use prebuild or custom native code, treat the app like a hybrid project. Review generated native changes instead of assuming the managed workflow insulates everything.
If your team is still deciding between Expo and a fully bare setup, this background article can help frame future upgrade effort: Expo vs React Native CLI: Which Setup to Choose in 2026.
Scenario 4: App with many native modules or private SDKs
This is the most fragile category in react native app development. The framework may upgrade cleanly while your business-critical native integrations do not.
- List every native dependency. Include payments, biometrics, notifications, media, maps, in-app purchases, SSO, VPN, device management, and internal SDKs.
- Check vendor support before coding. If a package has not acknowledged the target React Native range, assume extra work may be required.
- Build a focused test matrix. Verify each native feature independently instead of relying on a general app walkthrough.
- Look for architecture assumptions. Older packages may rely on legacy APIs, older Gradle settings, or outdated iOS integration patterns.
- Decide whether to patch, replace, or postpone. Sometimes the safest move is to delay the framework upgrade until one blocking native dependency is addressed.
What to double-check
This section is your reusable validation list. Run it after every upgrade attempt, even if the version change looked routine. This is where most react native breaking changes show up in practice.
Build and toolchain checks
- Node and package manager versions: confirm your team and CI use the same versions.
- Android build chain: Gradle, Android Gradle Plugin, SDK levels, Kotlin settings if applicable, and signing configs.
- iOS build chain: Xcode version, CocoaPods state, deployment target, build phases, and code signing.
- Hermes and JavaScript engine settings: confirm expected defaults and debug any startup regressions.
- Metro and Babel config: stale customizations often survive from older projects and conflict with newer defaults.
Runtime behavior checks
- Cold start and warm start: watch for hangs, white screens, delayed splash removal, or initialization loops.
- Navigation: test nested stacks, tab transitions, deep links, back behavior, and modals. A navigation package mismatch can look like a framework bug.
- Authentication: verify token restore, secure storage access, logout cleanup, and redirect flows.
- State hydration: persisted state can fail silently after dependency changes.
- Network and API boot flow: check interceptors, retries, SSL handling, and startup fetches.
- Forms and keyboard handling: layout shifts and focus issues are common after UI or platform updates.
- Notifications: local notifications, push token registration, permission prompts, and open-from-notification paths.
- Media and device APIs: camera, microphone, file access, image picker, background tasks, and permissions.
Performance checks
- Startup time: compare before and after, even informally, to catch regressions early.
- Scroll performance: heavy lists, image grids, and animated headers are useful canaries.
- Animation smoothness: gesture-based transitions and shared element style interactions deserve attention.
- Memory use on older devices: upgrades can surface issues that newer simulators hide.
If performance validation is part of your release criteria, these articles make good follow-up reads: Adaptive Frame Targets: Implementing Runtime Performance Modes in React Native and What Steam’s Crowd-Sourced Framerate Estimates Teach Mobile Teams About Real-World Performance.
Testing and release checks
- Unit and integration tests: update mocks and setup files if native APIs changed.
- E2E flows: prioritize login, onboarding, checkout, subscription, and key admin paths.
- Crash reporting: confirm symbols, source maps, and release identifiers still upload correctly.
- Analytics and telemetry: verify startup events and screen tracking after navigation or lifecycle changes.
- CI/CD: run the same build path your team uses for release, not only local commands.
- Store artifacts: validate APK, AAB, and iOS archive output before calling the upgrade complete.
For teams with stricter release processes, it also helps to review adjacent operational guidance such as Rapid-Response Playbook: Preparing React Native Apps for Surprise iOS Hotfixes and Architecting Mobile Event Pipelines: Reliable Telemetry from App to Marketing Systems.
Common mistakes
This section helps you avoid the most expensive upgrade habits. Most are not technical limits; they are sequencing problems.
- Upgrading too many things at once. If you change React Native, navigation, state management, lint rules, and TypeScript config together, root cause becomes hard to isolate.
- Skipping compatibility review. A quick version bump without checking peer dependencies is the fastest path to cryptic native errors.
- Testing only debug builds. Release builds can fail because of signing, minification, missing assets, symbol upload issues, or different initialization timing.
- Ignoring native diffs. In bare or customized apps, Android and iOS project changes matter as much as JavaScript changes.
- Trusting simulators alone. Permissions, notifications, performance, camera, and background behavior need real-device checks.
- Keeping stale patches forever. Temporary workarounds should be documented and revisited, or they become future upgrade blockers.
- Not documenting the final fix. The best upgrade asset is a short internal log of what changed, what broke, and how you resolved it.
- Waiting too long between upgrades. A small, regular maintenance rhythm is usually easier than a multi-version jump with years of drift.
A practical team habit is to keep a simple upgrade record with these fields: target version, package changes, native file edits, blocked libraries, test results, release status, and follow-up debt. That turns each upgrade into a lighter lift next time.
When to revisit
Use this checklist whenever your app crosses a version boundary, but also revisit it when the surrounding toolchain changes. A React Native upgrade can be forced indirectly by another dependency or release requirement.
Reopen this process when any of the following happens:
- Before seasonal planning cycles, when you are choosing between feature work and maintenance work.
- When workflows or tools change, such as a new CI runner, package manager policy, Xcode update, Android SDK update, or Expo SDK transition.
- When a critical library changes support ranges, especially navigation, push notifications, authentication, analytics, or a major native SDK.
- When you add a new native module that tightens your compatibility window.
- When performance regresses after routine dependency updates, suggesting a deeper stack mismatch.
- When release hotfixes start feeling fragile, which often means your project has accumulated too much version drift.
Here is a practical action plan you can reuse for every cycle:
- Once per quarter, audit your dependency risk. Identify which packages are core to runtime, native integration, and release flow.
- Check whether your current React Native version still fits the rest of your stack. Use a compatibility matrix rather than guessing.
- Decide whether the next upgrade is minor, major, or strategic. Strategic means the framework move is tied to a broader toolchain decision, such as Expo adoption, architecture cleanup, or release pipeline changes.
- Budget time for validation, not just implementation. The testing window is part of the upgrade, not an optional final step.
- Document what changed. The checklist becomes more valuable each time your team adds concrete notes from a real upgrade.
If you treat upgrades as routine maintenance instead of emergency work, they become much easier to manage. That is the real purpose of a strong react native guide: not just helping you get to the next version, but making the next five upgrades less disruptive than the last one.