Nothing is more frustrating than an app that works perfectly in development but crashes immediately in release mode. No error message, no logs, just a blank screen or instant crash.
I've debugged this issue multiple times. Here are the actual causes and fixes.
Getting Crash Logs
First, you need to see what's happening.
For Android:
adb logcat *:E | grep -i "react\|fatal\|crash"For iOS:
Open Xcode → Window → Devices and Simulators → Select your device → View Device Logs
Common Cause #1: Missing Environment Variables
In debug mode, you might be reading from a .env file. In release, those variables don't exist.
// This will crash in release if REACT_APP_API_URL is undefined
const API_URL = process.env.REACT_APP_API_URL;
fetch(API_URL + '/users'); // TypeError: Cannot read property of undefinedFix: Always provide fallbacks:
const API_URL = process.env.REACT_APP_API_URL ?? 'https://api.production.com';Or use react-native-config properly with release builds.
Common Cause #2: Console Statements
This one is sneaky. console.log with certain objects can crash release builds:
// Can crash in release
console.log(someCircularObject);Fix: Remove console statements in production:
npm install babel-plugin-transform-remove-console --save-devAdd to babel.config.js:
module.exports = {
presets: ['module:@react-native/babel-preset'],
env: {
production: {
plugins: ['transform-remove-console'],
},
},
};Common Cause #3: Hermes Issues
If you're using Hermes (default in newer RN versions), some JavaScript features might behave differently.
Check if Hermes is enabled:
const isHermes = () => !!global.HermesInternal;
console.log('Hermes enabled:', isHermes());Common Hermes gotchas:
// This can fail with Hermes
new Date('2024-01-28'); // Works
new Date('01-28-2024'); // Might fail
// Use ISO format instead
new Date('2024-01-28T00:00:00.000Z');Common Cause #4: ProGuard Stripping Code (Android)
ProGuard might remove classes it thinks are unused.
In android/app/proguard-rules.pro, add:
-keep class com.facebook.react.** { *; }
-keep class com.yourpackage.** { *; }
Common Cause #5: Native Module Not Linked
A native module might work in debug but fail in release if not properly linked.
Fix: Clean and rebuild:
# Android
cd android && ./gradlew clean && cd ..
# iOS
cd ios && rm -rf Pods && pod install && cd ..
# Rebuild
npx react-native run-android --variant=release
npx react-native run-ios --configuration ReleaseCommon Cause #6: AsyncStorage or Other Storage Issues
First launch after install might not have expected data:
// Crashes if user is null
const user = await AsyncStorage.getItem('user');
const parsed = JSON.parse(user); // null can't be parsedFix:
const user = await AsyncStorage.getItem('user');
const parsed = user ? JSON.parse(user) : null;Common Cause #7: Image/Asset Issues
Assets bundled in debug might not be included in release.
// Might work in debug, fail in release
<Image source={require('./local-image.png')} />Fix: Make sure assets are in the right location and rebuild:
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/resMy Debugging Checklist
- ✅ Check adb logcat / Xcode logs for actual error
- ✅ Remove all console.log statements
- ✅ Verify environment variables have fallbacks
- ✅ Clean build folders and node_modules
- ✅ Check for optional chaining on nullable values
- ✅ Test with Hermes disabled to isolate issues
- ✅ Verify all native modules are linked
Quick Test: Disable Hermes Temporarily
In android/gradle.properties:
hermesEnabled=false
In ios/Podfile:
:hermes_enabled => falseRebuild and test. If it works without Hermes, you've found your culprit.
Still Stuck?
Add error boundaries to catch and display errors:
import React from 'react';
import { Text, View } from 'react-native';
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
render() {
if (this.state.hasError) {
return (
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
<Text>Something went wrong:</Text>
<Text>{this.state.error?.toString()}</Text>
</View>
);
}
return this.props.children;
}
}Wrap your app with it to see what's actually crashing.
Hope this helps you ship your app!