Introduction
Recently, I embarked on upgrading my React Native application from version 0.74.3 to 0.79.5. What I initially thought would be a straightforward process turned into an intensive debugging session that revealed several common pitfalls in React Native upgrades. This post documents the challenges we faced and the solutions that ultimately got our app running smoothly.
The Upgrade Process
Initial Setup
We started by updating the core dependencies in package.json
:
{
"dependencies": {
"react": "19.0.0",
"react-native": "0.79.5"
},
"devDependencies": {
"@react-native-community/cli": "18.0.0",
"@react-native/babel-preset": "0.79.5",
"@react-native/eslint-config": "0.79.5",
"@react-native/metro-config": "0.79.5",
"@react-native/typescript-config": "0.79.5",
"@types/react": "^19.0.0",
"react-test-renderer": "19.0.0"
}
}
Challenge #1: Kotlin Version Compatibility
Problem: Kotlin compilation errors in native modules like react-native-pager-view
and react-native-screens
.
Error:
Kotlin compilation failed: incompatible Kotlin versions
Solution: Updated kotlinVersion
in android/build.gradle
from 1.9.22
to 2.1.20
:
buildscript {
ext {
kotlinVersion = "2.1.20"
}
}
Challenge #2: Java Heap Space During Jetifier Transformation
Problem: Build process running out of memory during AndroidX migration.
Error:
Java heap space: GC overhead limit exceeded
Solution: Increased JVM heap size in android/gradle.properties
:
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m
Challenge #3: Duplicate Classes from Android Support Library
Problem: Conflicts between old Android Support Library and AndroidX.
Error:
Duplicate class android.support.v4.app.INotificationSideChannel
Solution: Enabled Jetifier in android/gradle.properties
:
android.enableJetifier=true
Challenge #4: Node Binary Path Issues
Problem: Gradle couldn't locate the Node.js executable.
Error:
A problem occurred starting process 'command 'node''
Solution: Explicitly set the Node binary path in android/gradle.properties
:
NODE_BINARY=/Users/username/.nvm/versions/node/v22.15.1/bin/node
Challenge #5: Native Module Linking Errors
Problem: C++ linking errors with react-native-reanimated
and missing codegen files.
Error:
undefined symbol: worklets::JSLogger::warnOnJS
CMake Error: add_subdirectory given source ... which is not an existing directory
Solution:
- Updated
react-native-reanimated
to version3.10.1
- Ran codegen to generate missing native files:
npx react-native codegen
- Cleaned generated build directories to resolve duplicate CMake targets
Challenge #6: React Version Mismatch
Problem: The app was stuck on a black screen after splash screen due to React version incompatibility.
Error:
TypeError: undefined is not an object (evaluating 'ReactSharedInternals.S')
TypeError: Cannot read property 'default' of undefined
Solution: Ensured React and React Native versions were compatible:
- React Native 0.79.5 requires React 19.x
- Updated
react
to19.0.0
- Updated
@types/react
to^19.0.0
- Updated
react-test-renderer
to19.0.0
Challenge #7: TypeScript Module Resolution
Problem: TypeScript couldn't resolve custom module paths.
Error:
Cannot find module 'core/constants/screen-names'
Solution: Updated tsconfig.json
with proper path mappings:
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
"moduleResolution": "bundler",
"baseUrl": "./src",
"paths": {
"core/*": ["core/*"],
"setup/*": ["setup/*"],
"utils/*": ["utils/*"],
"components/*": ["components/*"]
}
}
}
Challenge #8: Metro Configuration Updates
Problem: Metro bundler needed updates for Node.js polyfills and module resolution.
Solution: Updated metro.config.js
:
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const config = {
resolver: {
alias: {
url: 'react-native-url-polyfill',
crypto: 'react-native-crypto',
stream: 'readable-stream',
buffer: '@craftzdog/react-native-buffer',
},
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
Key Configuration Updates
Android Configuration
android/app/build.gradle
:
- Updated React Native configuration block
- Added
autolinkLibrariesWithApp()
- Updated JSC flavor
- Simplified signing configurations
android/gradle.properties
:
- Enabled new architecture:
newArchEnabled=true
- Enabled Jetifier:
android.enableJetifier=true
- Increased heap size for memory-intensive builds
iOS Configuration
Gemfile
:
- Updated CocoaPods and ActiveSupport constraints
- Added Ruby standard library gems for compatibility
ios/Podfile
:
- Simplified React Native pods resolution
- Removed unnecessary imports
The Final Hurdle: App Stuck on Splash Screen
The most frustrating issue was the app getting stuck on a black screen after the splash screen. This was caused by:
-
Unreachable code in App.tsx: A
return
statement was preventing the main component from rendering - React version mismatch: The app was using React 18.2.0 instead of the required React 19.0.0
- Module resolution issues: TypeScript couldn't resolve custom module paths
Lessons Learned
- Always check React version compatibility: React Native 0.79.5 requires React 19.x
-
Clean builds are essential: Remove
node_modules
and rebuild when facing dependency issues - Memory allocation matters: Increase JVM heap size for complex Android builds
- Native modules need attention: Update Kotlin versions and run codegen for native modules
- TypeScript configuration is crucial: Ensure proper module resolution paths
- Metro configuration updates: Add necessary polyfills and transformer options
Timeline
The entire upgrade process took approximately a full day of intensive debugging, including:
- Initial dependency updates and configuration: 2 hours
- Android build issues and Kotlin compatibility: 4 hours
- iOS configuration and CocoaPods issues: 2 hours
- React version mismatches and module resolution: 3 hours
- Final testing and verification: 1 hour
The process involved significant back-and-forth debugging, with each fix often revealing new issues that needed to be addressed. This iterative approach, while time-consuming, was necessary to ensure all dependencies and configurations were properly aligned.
Conclusion
React Native upgrades can be challenging, but they're manageable with systematic debugging. The key is to:
- Address one issue at a time
- Keep detailed logs of errors
- Understand the relationship between React and React Native versions
- Don't hesitate to clean and rebuild when facing dependency issues
- Be prepared for a full day of debugging when upgrading across multiple major versions
The upgrade to React Native 0.79.5 was successful, and the app now runs smoothly with improved performance and access to the latest features.
This post documents a real React Native upgrade experience. While the specific app details have been anonymized, the technical challenges and solutions are genuine and can help others facing similar issues during their own upgrades.
Top comments (2)
but react native dev tools show nothing, blank . i'm stress , i can't see the log that very important to me for debugging react native app. the dozen AI i try to figure out why but nothing. now downgrade again to 0.76. pheww. any help maybe ?
amazing me that , on rn 0.77 above to 0.80 react native dev tool always blank. but in rn 0.76 fine the react dev tools showing up and connected