A step-by-step, version-agnostic React Native upgrade guide with inventory tables, cross-platform alignment commands, verification checks, and rollback procedures.

## TL;DR

- Capture a precise baseline tag and inventory before any change.

- Upgrade in scoped steps: RN core → iOS template/toolchain → Android template/toolchain → critical libraries.

- Verify with repeatable Debug-build checks, then graduate to Release builds on physical devices.

- Keep a fast rollback path via git tags, frozen lockfiles, and clean-native rebuilds.

- Gate risky changes with feature flags and staged rollouts; use OTA only when native ABI is stable.

## Prerequisites & Assumptions

- Clean git state: working tree committed or stashed; no untracked native artifacts (ios/build, android/.gradle, ios/Pods).

- CI parity: Node, Yarn/npm, Java, Xcode, CocoaPods, Android SDK/NDK versions match your CI agents exactly.

- Platform access: Apple Developer account and Google Play Console access for Release validation and staged rollout.

- Physical devices: Required for Hermes JIT/AOT behavior, billing libraries, and Release performance profiling.

- Convention: All versions, bundle IDs, scheme names, and paths are placeholders; replace with your project values.

## Architecture & Runtime Context

Understanding coupling points prevents silent regressions.

- Hermes vs JavaScriptCore: Hermes compiles JS to bytecode ahead-of-time (AOT on iOS, JIT+AOT on Android). Mixed Hermes/JSC settings across platforms cause ABI mismatches and crashes. Keep enableHermes / :hermes_enabled identical on iOS and Android.

- Metro cache: Metro caches module resolution and transforms. Native upgrades (RN version, native modules) invalidate this cache. Always run npx react-native start --reset-cache after native changes.

- Native toolchain coupling: Each RN version pins minimum Xcode, CocoaPods, AGP, Gradle wrapper, NDK, minSdkVersion, and iOS deployment target. Drifting from the template causes build failures or runtime crashes. Use the upgrade helper to read the exact requirements for your target version.

## Version Compatibility Matrix & Upgrade Helper Usage

Consult the official React Native release notes and the upgrade helper for the authoritative matrix. The table schema below shows what to record for your target version X.Y.Z.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Component</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Source of Truth</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Example Value (Constructed)</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Notes</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">React Native</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">reactnative.dev/versions / Upgrade Helper</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">0.76.x</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Target version</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Xcode</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Upgrade Helper diff / Release notes</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">15.4</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Minimum supported</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">CocoaPods</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Release notes</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">1.15.2</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Match team/CI</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">iOS Deployment Target</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">ios/Podfile template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">15.1</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">platform :ios, &#39;15.1&#39;</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">AGP</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">android/build.gradle template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">8.5.0</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">com.android.application</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Gradle Wrapper</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">gradle-wrapper.properties template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">8.7</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">distributionUrl</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">NDK</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">android/app/build.gradle template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">26.1.10909125</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Side-by-side install OK</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">compileSdkVersion</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">34</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Google Play requirement</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">minSdkVersion</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">24</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Library minimums may raise this</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">targetSdkVersion</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Template diff</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">34</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Google Play requirement</td></tr></tbody>
</table>
</div>
Fetch the template diff for your target version:

# Dry-run CLI upgrade (uses rn-diff-purge under the hood)
npx @react-native-community/cli upgrade --dry-run X.Y.Z

# Or review the web upgrade helper (search "React Native upgrade helper" on reactnative.dev) 
 Review diffs via git diff after running the upgrade command, or inspect the web helper's file-by-file changes. Prefer manual template alignment when your project has heavy customizations (custom MainApplication, AppDelegate, build scripts, or forked native modules).

## Inventory

Capture the exact runtime and build state before any change. Record in a ticket or README-upgrade.md.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Item</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Where / Command</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Example Value (Constructed)</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Notes</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">React Native</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">package.json or node -p &quot;require(&#39;./package.json&#39;).dependencies[&#39;react-native&#39;]&quot;</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">0.74.5</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Current version</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Node &amp; Package Managers</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">node -v, npm -v, yarn -v, pnpm -v</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Node 20.12, Yarn 4.1</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Match CI</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">iOS Toolchain</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">xcodebuild -version, pod --version</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Xcode 15.3, CocoaPods 1.15.2</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Team sync</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Android Toolchain</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">cat android/gradle/wrapper/gradle-wrapper.properties, grep &quot;com.android.tools.build:gradle&quot; android/build.gradle</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Gradle 8.5, AGP 8.4.0</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Align with RN template</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">SDK Levels</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">android/app/build.gradle, ios/Podfile</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">minSdk 23, targetSdk 34, compileSdk 34, iOS 15.1</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Store policies</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Hermes</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">grep hermes android/app/build.gradle ios/Podfile</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">enabled</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Consistency required</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Critical Libraries</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">npm ls --depth=0 | grep -E &quot;navigation|reanimated|gesture|stripe|billing&quot;</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">@react-navigation/native 6.x, react-native-reanimated 3.x</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">PeerDependency constraints</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">CI Parity</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">CI config (.github/workflows, bitrise.yml)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Node 20.12, Xcode 15.3, JDK 17</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Must match local</td></tr></tbody>
</table>
</div>
Expo notes (constructed):

- Managed workflow: note SDK version (e.g., SDK 51); run npx expo doctor before upgrading.

- Bare workflow: treat as standard RN app; expo prebuild --clean can validate native config after changes.

## Safe Configuration Path

Scope and sequencing keep the blast radius small. Promote changes in observable steps.

### 1. Choose Target Version & Create Baseline

git checkout -b upgrade/rn-X.Y.Z
git tag pre-rn-X.Y.Z # baseline tag for fast revert 
 Commit lockfiles (yarn.lock / package-lock.json) if not already tracked. Record the inventory table in the branch description.

### 2. Define a Narrow Pilot Flow

Select one screen touching JS logic, native UI, and network I/O (constructed example: Settings → Login → Fetch Profile). Define pass/fail checks: no redbox, API 200, token persisted, UI renders.

### 3. Upgrade React Native Core & Apply Template Diffs

# JavaScript dependency (pick one)
npm install react-native@X.Y.Z --save
# or
yarn add react-native@X.Y.Z

# Apply template diffs via CLI (uses rn-diff-purge)
npx react-native upgrade X.Y.Z 
 Resolve prompts carefully: prefer keeping project-specific changes. Inspect git diff immediately; commit the RN bump and template alignment separately.

### 4. Dependency Upgrade Order (PeerDependency-Aware)

Upgrade critical libraries one at a time, committing after each. Read changelogs for minimum RN/Android/iOS requirements.

- react-native (core)

- @react-native-community/* (cli, netinfo, async-storage, etc.)

- Navigation (@react-navigation/*)

- react-native-gesture-handler, react-native-reanimated (tight RN coupling)

- react-native-stripe-sdk, react-native-google-play-billing (store policy coupling)

- Image loaders, analytics, crash reporting, others

## iOS Alignment

Align Xcode project, CocoaPods, and signing to the target RN template.

### Podfile Configuration (Constructed Example)

# ios/Podfile
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '15.1' # from template diff
prepare_react_native_project!

target 'YourApp' do
 config = use_native_modules!
 use_react_native!(
 :path => config[:reactNativePath],
 :hermes_enabled => true, # match Android
 :fabric_enabled => false, # enable when ready
 :flipper_configuration => FlipperConfiguration.disabled, # or .enabled for Debug
 :app_path => "#{Pod::Config.instance.installation_root}/.."
 )
 post_install do |installer|
 react_native_post_install(installer)
 # Workaround for Xcode 15+ signing in CI
 installer.pods_project.targets.each do |target|
 target.build_configurations.each do |config|
 config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
 end
 end
 end
end 

### Install & Build Debug

 cd ios
pod install --repo-update
cd ..

# Debug build for simulator (CI-friendly)
xcodebuild -workspace ios/YourApp.xcworkspace \
 -scheme YourApp \
 -configuration Debug \
 -sdk iphonesimulator \
 -derivedDataPath ios/build \
 clean build 
 Key checks: Deployment target matches template; hermes_enabled consistent; Flipper disabled for Release or aligned to RN version; signing set to CODE_SIGNING_ALLOWED=NO for CI.

## Android Alignment

Align Gradle wrapper, AGP, NDK, SDK levels, and Hermes/Fabric flags.

### Gradle Wrapper & AGP (Constructed for RN 0.76 Target)

# Update wrapper
cd android
./gradlew wrapper --gradle-version 8.7
cd .. 
 // android/build.gradle (project level)
plugins {
 id 'com.android.application' version '8.5.0' apply false
 id 'com.android.library' version '8.5.0' apply false
 id 'org.jetbrains.kotlin.android' version '1.9.20' apply false
} 

### App Module SDK & Hermes (Constructed)

 // android/app/build.gradle
android {
 namespace "com.yourcompany.yourapp"
 compileSdkVersion 34
 ndkVersion "26.1.10909125"

 defaultConfig {
 applicationId "com.yourcompany.yourapp"
 minSdkVersion 24
 targetSdkVersion 34
 versionCode 1
 versionName "1.0"
 }

 // Hermes & Fabric flags (match iOS)
 project.ext.react = [
 enableHermes: true,
 enableFabric: false
 ]
} 

### ProGuard / R8 Keep Rules (Constructed)

 # android/app/proguard-rules.pro
# Reanimated
-keep class com.swmansion.reanimated.** { *; }
-keepclassmembers class com.swmansion.reanimated.** { *; }

# Stripe
-keep class com.stripe.** { *; }
-dontwarn com.stripe.**

# Google Play Billing
-keep class com.android.billingclient.** { *; }
-keep class com.google.android.play.core.** { *; } 

### Clean Build Debug

 cd android
./gradlew clean assembleDebug --no-daemon
cd .. 

## Library Migrations

 Follow the dependency upgrade order from Safe Configuration Path. For each library:

- Bump version in package.json (respect peerDependency ranges).

- Run npm install / yarn install .

- Run cd ios && pod install && cd .. if the library has native iOS code.

- Build Debug on both platforms.

- Run pilot flow.

- Commit with message: upgrade: <library>@<version> – <intent> .

PeerDependency watchouts: react-native-reanimated and react-native-gesture-handler often lock to specific RN minor versions. react-native-stripe-sdk and react-native-google-play-billing enforce minSdk / compileSdk floors. Read their package.json peerDependencies before upgrading.

## Verification & Diagnostics

Prove the upgrade works with repeatable checks. Start in Debug; graduate to Release on physical devices.

### Debug Build & Pilot Flow

# Android
npx react-native run-android

# iOS Simulator
npx react-native run-ios 
 Execute pilot flow: Launch → Navigate → Login (API 200, token stored) → Fetch Profile (render, pull-to-refresh).

### Logs & Diagnostics

# Android: filter RN/JS logs
adb logcat *:S ReactNative:V ReactNativeJS:V

# iOS: recent logs (replace YourApp)
log show --predicate 'process == "YourApp"' --style syslog --last 2m

# Metro cache reset
npx react-native start --reset-cache 

### Static Checks

 npm test -- --watchAll=false
npx tsc --noEmit
npx eslint . 

### Release Build Smoke Test (Physical Device Required)

 # Android Release (includes JS bundle)
./gradlew assembleRelease bundleReleaseJsAndAssets

# iOS Release (CI-friendly, no signing)
xcodebuild -workspace ios/YourApp.xcworkspace \
 -scheme YourApp \
 -configuration Release \
 -sdk iphoneos \
 -derivedDataPath ios/build \
 CODE_SIGNING_ALLOWED=NO \
 clean build 
 Install Release builds on physical devices. Test Hermes JIT/AOT, billing flows, Stripe, and background/foreground transitions.

### Performance Validation (Constructed Examples)

- Cold start: Add console.time('bootstrap') at app entry; console.timeEnd('bootstrap') in root component useEffect. Extract from adb logcat / os_log. Compare before/after; drift within 10–15% is acceptable.

- Frame drops: Enable why-did-you-render in Debug or capture Systrace ( npx react-native profile-hermes ).

- Bundle size:

npx react-native bundle --dev false --platform ios \
 --entry-file index.js \
 --bundle-output /tmp/main.jsbundle \
 --assets-dest /tmp
 # Analyze with hermes-bytecode-analyzer if Hermes enabled 

### Security & Compliance Checks

- Verify TLS 1.2+ on all network requests (Charles/ProxyMan).

- Confirm no __DEV__ flags, console.log of secrets, or debuggable true in Release AndroidManifest.xml / Entitlements.plist.

- Validate Stripe / Google Play Billing SDK versions meet current store policy minimums.

### Verification Table (Adapt to Your Project)

 Check How to Run Pass Criteria Notes 
 Build Android Debug ./gradlew assembleDebug Build succeeds, app launches Constructed example 
 Build iOS Debug xcodebuild clean build (simulator) Simulator launches app Constructed example 
 Pilot flow works Manual navigation No redbox; UI renders; API 200 Constructed example 
 Logs clean adb logcat, log show No crash/severe warnings Constructed example 
 Static checks pass npm test, tsc, eslint Zero failures Constructed example 
 Build Android Release ./gradlew assembleRelease bundleReleaseJsAndAssets APK/AAB produced; installs on device Physical device 
 Build iOS Release xcodebuild -configuration Release .app produced; installs on device Physical device 
 Release pilot flow Physical device test No crashes; billing/Stripe work Hermes AOT, real network 
 Performance baseline console.time cold start Within 10–15% of pre-upgrade Constructed example 
 Security scan Proxy TLS, grep __DEV__ TLS 1.2+; no debug leaks Constructed example 

## Failure Modes & Recovery

 Targeted diagnostics for common upgrade symptoms.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Symptom</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Likely Cause</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Action &amp; Commands</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">CocoaPods spec/CDN error</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Stale repo or lockfile</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">cd ios &amp;&amp; rm -rf Pods Podfile.lock &amp;&amp; pod repo update &amp;&amp; pod install &amp;&amp; cd ..</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Xcode duplicate symbols / Flipper crash</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Flipper version mismatch</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Disable Flipper in Podfile: <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">:flipper_configuration =&gt; FlipperConfiguration.disabled</code>; rebuild; re-enable after aligning.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Android duplicate class</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Transitive dependency conflict</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">cd android &amp;&amp; ./gradlew :app:dependencies --configuration debugCompileClasspath &gt; debugDeps.txt &amp;&amp; cd ..</code>; align versions.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Hermes bytecode mismatch / launch crash</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Inconsistent Hermes flag or stale caches</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Ensure enableHermes / :hermes_enabled identical; <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">cd ios &amp;&amp; rm -rf build Pods Podfile.lock &amp;&amp; pod install &amp;&amp; cd ..</code>; <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">cd android &amp;&amp; ./gradlew clean &amp;&amp; cd ..</code>; <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">npx react-native start --reset-cache</code>.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Metro &quot;Unable to resolve module&quot;</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Stale cache / watchman</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">rm -rf node_modules &amp;&amp; npm ci &amp;&amp; npx react-native start --reset-cache</code>; <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">watchman watch-del-all</code>.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Xcode &quot;Command PhaseScriptExecution failed&quot; (Hermes dSYM)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">dSYM generation race</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Clean derived data; ensure DEBUG_INFORMATION_FORMAT = dwarf-with-dsym only for Release; disable Hermes dSYM in Debug if persistent.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Android &quot;Manifest merger failed&quot;</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">minSdk / targetSdk conflict</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Raise minSdkVersion in android/app/build.gradle to satisfy all libraries; ensure tools:node=&quot;replace&quot; for conflicting permissions.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">ProGuard/R8 crashes (Release only)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Missing keep rules</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Add keep rules for reanimated, Stripe, Play Billing (see Android Alignment); test Release build after each addition.</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Release-only network/TLS failure</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Cleartext traffic or cert pinning</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Check android:usesCleartextTraffic; verify network_security_config.xml; test with ProxyMan/Charles.</td></tr></tbody>
</table>
</div>

## Rollback Procedures

### Local Rollback (Fast)

# Reset to baseline tag
git reset --hard pre-rn-X.Y.Z

# Restore JS deps
npm ci --prefer-offline # or yarn install --frozen-lockfile

# iOS clean rebuild
cd ios
rm -rf Pods Podfile.lock build
pod install
cd ..

# Android clean rebuild
cd android
./gradlew clean
cd .. 

### CI Rollback

- Revert the upgrade PR/merge commit.

- Trigger pipeline on main; it will use frozen lockfiles and cached toolchains to rebuild the prior version.

- Verify artifact publication (TestFlight, Play Console internal track).

### Production Rollback Strategies

- Staged rollout: Pause or decrease rollout percentage in Play Console / App Store Connect when crash rate spikes.

- Feature flags: Disable risky library features remotely (LaunchDarkly, Firebase Remote Config, custom) while keeping app version live.

- OTA JS update (CodePush, Expo Updates, custom): Revert JS bundle only if native ABI is unchanged. If native modules were added/removed or RN version changed native interfaces, ship a hotfix binary.

### Post-Rollback Validation

- Prior version builds and launches on both platforms.

- Pilot flow passes; logs clean.

- Crash rates and store reviews return to baseline.

## Operations Checklist

### Preparation

- [ ] Create branch upgrade/rn-X.Y.Z; tag baseline pre-rn-X.Y.Z.

- [ ] Complete inventory: Node, pkg mgr, RN, iOS/Android toolchains, Hermes, critical libs, CI parity.

- [ ] Define narrow pilot flow with pass/fail checks.

### Upgrade Steps

- [ ] Bump react-native; npm install / yarn add.

- [ ] Apply template diffs: npx react-native upgrade X.Y.Z.

- [ ] iOS: pod install; confirm Hermes; build Debug.

- [ ] Android: update Gradle wrapper & AGP; confirm SDK levels; build Debug.

- [ ] Upgrade critical libraries one by one (order per Safe Configuration Path); commit after each.

### Verification

- [ ] Launch both platforms; run pilot flow end-to-end.

- [ ] Check logs: no crashes/severe warnings.

- [ ] Run tests: unit, TypeScript, lint.

- [ ] Sanity-check performance (cold start, navigation).

- [ ] Validate REST API, Stripe, Google Play Billing on physical devices.

### Stabilization

- [ ] Build Release variants locally once Debug is clean.

- [ ] Re-run pilot and extended smoke tests on Release builds.

- [ ] Document changes and any manual steps.

### Recovery Readiness

- [ ] Baseline tag reachable; lockfiles committed.

- [ ] Clean-rebuild commands documented and tested.

- [ ] Feature flags configured for risky areas.

### Handoff

- [ ] Share inventory, diffs, verification results.

- [ ] Plan rollout with monitoring and rollback trigger.

## CI/CD Integration

 Run inventory, verification, and build steps in pipeline. Fail fast on regressions. Publish artifacts for QA.

### GitHub Actions Snippet (Constructed)

# .github/workflows/rn-upgrade-validation.yml
name: RN Upgrade Validation
on:
 pull_request:
 branches: [main]
 paths:
 - 'package.json'
 - 'yarn.lock'
 - 'ios/**'
 - 'android/**'

jobs:
 validate:
 runs-on: macos-latest # or self-hosted with Xcode/Android SDK
 timeout-minutes: 60
 steps:
 - uses: actions/checkout@v4
 with:
 fetch-depth: 0 # needed for git diff / tags

 - name: Setup Node
 uses: actions/setup-node@v4
 with:
 node-version: '20.12'
 cache: 'yarn'

 - name: Setup Java
 uses: actions/setup-java@v4
 with:
 distribution: 'temurin'
 java-version: '17'

 - name: Setup Ruby
 uses: ruby/setup-ruby@v1
 with:
 ruby-version: '3.2'
 bundler-cache: true

 - name: Cache CocoaPods
 uses: actions/cache@v4
 with:
 path: ios/Pods
 key: pods-${{ hashFiles('ios/Podfile.lock') }}

 - name: Cache Gradle
 uses: actions/cache@v4
 with:
 path: |
 ~/.gradle/caches
 ~/.gradle/wrapper
 key: gradle-${{ hashFiles('android/gradle/wrapper/gradle-wrapper.properties', 'android/build.gradle') }}

 - name: Install JS deps
 run: yarn install --frozen-lockfile

 - name: Inventory (baseline capture)
 run: |
 node -v
 yarn -v
 node -p "require('./package.json').dependencies['react-native']"
 xcodebuild -version
 pod --version
 cat android/gradle/wrapper/gradle-wrapper.properties
 grep "com.android.tools.build:gradle" android/build.gradle

 - name: TypeScript & Lint
 run: |
 npx tsc --noEmit
 npx eslint .

 - name: Unit Tests
 run: yarn test --watchAll=false --ci

 - name: iOS Debug Build
 run: |
 cd ios
 pod install --repo-update
 cd ..
 xcodebuild -workspace ios/YourApp.xcworkspace \
 -scheme YourApp \
 -configuration Debug \
 -sdk iphonesimulator \
 -derivedDataPath ios/build \
 clean build

 - name: Android Debug Build
 run: |
 cd android
 ./gradlew assembleDebug --no-daemon
 cd ..

 - name: Upload Android Debug APK
 uses: actions/upload-artifact@v4
 with:
 name: app-debug
 path: android/app/build/outputs/apk/debug/app-debug.apk

 # Optional: Release builds on tagged commits or manual dispatch
 # - name: Android Release Build
 # if: github.event_name == 'workflow_dispatch'
 # run: cd android && ./gradlew assembleRelease bundleReleaseJsAndAssets --no-daemon 
 Bitrise / CircleCI equivalents: Mirror the same steps—cache CocoaPods/Gradle, freeze lockfiles, run typecheck/lint/test, build Debug on both platforms, publish artifacts. Gate Release builds on manual approval or tag push.

## Security & Compliance Notes

- Transport security: Verify all network requests use TLS 1.2+; no cleartext traffic in Release. Inspect Network Security Config (Android) and NSAppTransportSecurity (iOS).

- Debug flags: Ensure android:debuggable="false" in Release AndroidManifest.xml; DEBUG=0 / __DEV__=false in JS bundle; no console.log of PII/tokens.

- Billing compliance: Stripe SDK and Google Play Billing Library must meet current store minimums (e.g., Play Billing Library 6+ for Android 14 target). Test purchase flows on physical devices with test accounts.

- Entitlements & permissions: Audit Entitlements.plist and AndroidManifest.xml for unused permissions (location, camera, microphone) after native module upgrades.

- Supply chain: npm audit / yarn audit post-upgrade; pin transitive dependencies if critical CVEs appear.

## Conclusion

You now have a practical, low-risk path to upgrade React Native: make the current state explicit with a precise inventory; change one bounded slice at a time, starting with a narrow pilot flow; align iOS and Android templates and toolchains, then upgrade libraries in dependency order; verify outcomes with Debug builds, static checks, Release builds on physical devices, performance baselines, and security scans; recover quickly using committed baseline tag, frozen lockfiles, clean-native rebuilds, and feature flags. Repeat this process for each version step, and you will reduce surprises, shorten failure recovery, and keep shipping while modernizing your app.