name: upgrade-react-native description: Upgrade the React Native fixture app to a new version. Covers JS deps, Android (Gradle, Kotlin, SDK), iOS (Podfile, pbxproj), Metro config, and third-party libraries.
Upgrade React Native Fixture App
Overview
The fixture app lives in fixture/react-native/. It is the primary test vehicle for FlashList on iOS and Android. The web fixture (fixture/web/) uses Expo and is independent — check it builds after the upgrade but it does not need the same dependency changes.
Step 1 — Research the Target Version
Check the latest stable RN version:
npm view react-native@latest versionUse the rn-diff-purge repo to see the exact template diff between your current and target version:
https://raw.githubusercontent.com/react-native-community/rn-diff-purge/release/<version>/RnDiffApp/<file>Key files to fetch:
package.json— React version, CLI versions, dev dep versionsandroid/build.gradle— SDK versions, Kotlin versionandroid/app/build.gradle— plugin names, dependency patternsandroid/gradle.properties— feature flags (newArch, hermes, edgeToEdge)android/gradle/wrapper/gradle-wrapper.properties— Gradle versionandroid/settings.gradle— plugin management patternandroid/app/src/main/java/com/rndiffapp/MainApplication.kt— app initialization patternios/Podfile— pod configuration, post_install hooksios/RnDiffApp/AppDelegate.swift— app delegate patternmetro.config.js— Metro config API changes
Check third-party library compatibility with the target RN version:
react-native-reanimated— check compatibility tablereact-native-gesture-handler— supports 3 latest RN minorsreact-native-screens,react-native-safe-area-context— usually latest works@react-navigation/*— check for breaking changes- Any image library (
@d11/react-native-fast-image, etc.)
Step 2 — Update Dependencies
fixture/react-native/package.json
Update in this order:
reactandreact-native— match the template@react-native/*dev packages — must match the RN minor (e.g.,@react-native/babel-preset@0.84.1for RN 0.84.1)@react-native-community/cli*— match the template- Third-party native libraries — bump to versions compatible with the target RN
- Any new peer dependencies (e.g., reanimated 4 requires
react-native-worklets)
Babel config
Check if any Babel plugins moved packages. Example: reanimated 4 moved react-native-reanimated/plugin to react-native-worklets/plugin.
Metro config
Metro's internal module paths change between versions. Common breakage:
metro-config/src/defaults/exclusionList— in newer Metro this moved tometro-config/private/defaults/exclusionListand exports a.defaultinstead of a direct function- Always verify the import works:
node -e "console.log(typeof require('<path>'))"
Step 3 — Update Android
android/build.gradle
buildToolsVersion,compileSdkVersion,targetSdkVersion— match templatekotlinVersion— match templatendkVersion— match template (usually unchanged between minors)
android/gradle/wrapper/gradle-wrapper.properties
- Update Gradle distribution URL to match template
android/gradle.properties
- Remove deprecated flags (e.g.,
android.enableJetifier,FLIPPER_VERSION) - Add new flags (e.g.,
edgeToEdgeEnabled) - Update JVM args if template changed them
android/app/build.gradle
- Update plugin names if changed (e.g.,
kotlin-android→org.jetbrains.kotlin.android) - Remove unused imports (e.g.,
import com.android.build.OutputFile) - Check
autolinkLibrariesWithApp()is present
android/settings.gradle
- Match template structure
- Remove manual project includes for pure-JS libraries (flash-list has no native Android code)
MainApplication.kt
- This changes significantly between major RN versions. Always diff against the template.
- Preserve custom code:
AppPackage()registration andI18nUtil.allowRTL()for RTL support. - Key pattern changes across versions:
- 0.79:
SoLoader.init()+DefaultNewArchitectureEntryPoint.load()+ReactNativeHost - 0.84:
loadReactNative(this)+getDefaultReactHost()with lazy delegate (no ReactNativeHost)
- 0.79:
Step 4 — Update iOS
ios/Podfile
- Match template structure
- Remove deprecated env vars (e.g.,
ENV['RCT_NEW_ARCH_ENABLED']when new arch is the default) - Remove deprecated helper calls (e.g.,
get_default_flags()) - Keep project-specific customizations (
use_frameworks! :linkage => :staticif needed)
ios/FlatListPro.xcodeproj/project.pbxproj
- Update
IPHONEOS_DEPLOYMENT_TARGETto match the RN minimum (e.g., 15.1 for RN 0.76+) - Pod install will update header search paths and build settings automatically
ios/FlatListPro/Info.plist
- Add any new required plist keys (e.g.,
RCTNewArchEnabled)
Clean install
cd fixture/react-native
rm -rf node_modules yarn.lock
yarn install
cd ios && rm -rf Pods Podfile.lock && pod install && cd ..
Step 5 — Build and Verify
Build the flash-list library first
yarn build # from repo root — compiles src/ → dist/
iOS
cd fixture/react-native
xcodebuild -workspace ios/FlatListPro.xcworkspace -scheme FlatListPro \
-configuration Debug -sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
Android
cd fixture/react-native
yarn react-native run-android
Web
cd fixture/web && yarn install && npx expo export --platform web
Step 6 — Run Tests
Unit tests
yarn test # from repo root — 181+ tests must pass
E2E tests (iOS)
cd fixture/react-native
yarn e2e:build:ios
yarn e2e:test:ios
Screenshot reference updates: Visual diff tests (e.g., Carousel orientation) will fail after an RN upgrade because rendering changes slightly. To regenerate references:
- Delete the old reference directory (e.g.,
e2e/artifacts/ios/Carousel_landscape/) - Run the test — it creates a new reference and fails with "no reference present"
- Run again — it passes using the new reference
- Repeat for each failing screenshot (the test stops at the first missing reference per run)
Common Pitfalls
- Metro
exclusionListimport — Metro's internal API paths change between versions. Always verify the import resolves before starting Metro. - Stale Metro on wrong port — Kill ALL Metro instances before testing. Another project's Metro on a different port can cause "version mismatch" errors if the app connects to it.
react-native-reanimatedmajor version — Major bumps (3→4) require Babel plugin changes and may add new peer dependencies (react-native-worklets).- Gradle version jumps — RN upgrades often bump Gradle (e.g., 8.x→9.x). This can break custom Gradle scripts. Check build warnings for deprecations.
IPHONEOS_DEPLOYMENT_TARGET— Must match or exceed the RN minimum. Pod install updates most settings, but the project-level target in pbxproj must be set manually.Info.plistnew keys — Some RN versions require new plist entries (e.g.,RCTNewArchEnabled). Check the template's Info.plist diff.- Legacy arch removal — Starting with RN 0.82+, legacy architecture code is being removed. Ensure all dependencies support new arch.