React Native App Crashes on Release Build Only
An app that runs perfectly in development but crashes only in release builds is one of the most frustrating categories of React Native bugs, precisely because the debug build gives you no warning at all — the crash only appears once you’ve already built and shipped something closer to production.
The Problem
Your app works fine with npx react-native run-android or run-ios in debug mode, but a release build (via ./gradlew assembleRelease, Xcode’s Release scheme, or a build service like EAS) crashes on launch or crashes when reaching a specific screen, often with a generic native crash log that doesn’t point clearly to your JavaScript code.
Why It Happens
Release builds behave differently from debug builds in several ways that can each independently cause this. The most common causes are:
- Code minification or the Hermes JS engine’s release optimizations exposing a bug that debug mode’s less aggressive settings never triggered, particularly around dynamic property access or code that assumes a specific variable name survives minification
- Environment variables or config values that were only set in your local
.envfile for development, and were never properly injected into the release build process, leaving the app trying to useundefinedvalues at runtime - Native Android ProGuard/R8 rules stripping out a class or method that a native module relies on via reflection, since ProGuard’s default rules don’t know to preserve code it can’t see being referenced directly
- A dependency that behaves differently (or isn’t included at all) in release mode, commonly debugging-only libraries that were never meant to run outside development
The Fix
First, get an actual crash log rather than guessing. On Android, connect a device via USB even for a release build and read the logs directly:
adb logcat *:E
On iOS, use Xcode’s device console (Window > Devices and Simulators) or check crash logs synced through Xcode Organizer, since a release build crash won’t show up in the Metro terminal at all.
If the crash log points to a missing class or method (common with ProGuard on Android), add a keep rule for the specific library causing the issue in android/app/proguard-rules.pro:
# Example: keep rule for a native module using reflection
-keep class com.yourlibrary.** { *; }
-dontwarn com.yourlibrary.**
If the issue is related to environment variables, confirm your build pipeline actually injects them into the release build the same way your local development environment does. A common gap is a .env file that’s gitignored (correctly, for security) but was never configured as a secret in your CI/CD or build service, so the release build silently falls back to undefined values:
console.log('API_URL:', process.env.API_URL); // add temporarily to confirm it's actually set
If you suspect Hermes-specific behavior, try temporarily disabling Hermes for a release build to see if the crash disappears, which helps isolate whether the engine itself is the variable:
// android/app/build.gradle
project.ext.react = [
enableHermes: false
]
If disabling Hermes resolves the crash, the root cause is almost certainly something in your JS code that behaves differently under Hermes’s bytecode compilation — commonly around Intl API usage, certain regex patterns, or code relying on JS engine-specific behavior that isn’t part of the language spec.
Still Not Working?
If the crash log is too generic to point to a specific cause, bisect the issue by commenting out large chunks of app functionality (or reverting to an earlier commit known to work in release mode) and rebuilding in release mode each time, narrowing down which specific screen, component, or dependency introduces the crash — this is slower than reading a clear stack trace, but reliable when the native crash log itself doesn’t give you enough to go on directly.