Importance of source maps for React Native
Without source maps, a crash in Firebase Crashlytics looks like a meaningless string:
Fatal Exception: com.facebook.react.common.JavascriptException [email protected]:1:92847 [email protected]:1:15234 The number 1:92847 — position in the minified bundle. We've seen teams lose hours trying to debug bugs from such stack traces. Source map turns this into a readable path: onButtonPress @ src/screens/PaymentScreen.tsx:147:23. Without it, an average project spends 2-4 hours per crash — with 15-30 crashes per month that's 30-120 hours of debugging. Our job is to configure automatic source map upload to the monitoring service, so every crash contains actionable information. We do this turnkey, with integration into your CI, in 4 hours — 2 days. Over 5 years, we've set up this system for more than 50 React Native projects.
How to upload source maps to Firebase Crashlytics
Use Firebase CLI: firebase crashlytics:mappingfile:upload --app "$FIREBASE_APP_ID" /path/to/map. For projects with Hermes, you need to compose the two-level source maps first. Sentry is simpler: it composes maps automatically upon upload, making setup 2x faster. Here is a step-by-step guide:
- Install Firebase CLI and authenticate:
npm install -g firebase-tools && firebase login:ci. - Build the release bundle with source maps.
- If using Hermes, perform source map composition.
- Upload the source map to Crashlytics:
firebase crashlytics:mappingfile:upload --app "$FIREBASE_APP_ID" android/app/build/generated/sourcemaps/react/release/index.android.bundle.map - For Sentry, use
sentry-cli:
sentry-cli releases new "$RELEASE_VERSION" sentry-cli sourcemaps upload --org "$SENTRY_ORG" --project "$SENTRY_PROJECT" --release "$RELEASE_VERSION" android/app/build/generated/sourcemaps/react/release/ - Verify that the version in SDK matches the one passed in CLI.
Example GitHub Actions integration – source map upload
- name: Upload Source Maps to Crashlytics run: | node node_modules/react-native/scripts/compose-source-maps.js \ android/app/build/generated/sourcemaps/react/release/index.android.bundle.packager.map \ android/app/build/generated/sourcemaps/react/release/index.android.bundle.compiler.map \ -o /tmp/composed.map firebase crashlytics:mappingfile:upload --app "$FIREBASE_APP_ID_ANDROID" /tmp/composed.map env: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} Generating source maps
React Native minifies and merges all JS code into one file (index.android.bundle / main.jsbundle) in production bundle. Simultaneously, a source map (index.android.bundle.map) is generated — a mapping table between positions in the bundle and original source code. Crashlytics and Sentry accept these source maps and store them on their servers. When a crash occurs, they automatically apply the mapping and show the original stack trace. Commands for generation:
# Android react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --sourcemap-output android/app/src/main/assets/index.android.bundle.map # iOS react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --sourcemap-output ios/main.jsbundle.map In the standard ./gradlew bundleRelease, source map is generated automatically in app/build/generated/sourcemaps/react/release/. But there's a problem: with Hermes compilation, a composite source map is needed — Hermes creates a second mapping level (bytecode → JS bundle) which must be composed with the first (JS bundle → TypeScript).
Why Hermes adds complexity to source maps
Hermes compiles the JS bundle into bytecode, introducing an extra mapping layer. Without composition, monitoring services get mapping only to the JS bundle, not to the original source code. For example, the stack points to a line in the bundle, not in the *.tsx file. The script compose-source-maps.js merges both mappings. For projects with Hermes (enabled by default since RN 0.70+), execute:
node node_modules/react-native/scripts/compose-source-maps.js \ android/app/build/generated/sourcemaps/react/release/index.android.bundle.packager.map \ android/app/build/generated/sourcemaps/react/release/index.android.bundle.compiler.map \ -o android/app/build/generated/sourcemaps/react/release/index.android.bundle.map Without this step, Firebase Crashlytics will show a stack trace referencing JS bundle lines, not the original TypeScript file. Sentry, on the other hand, automatically composes source maps upon upload, making it 2x simpler to set up for Hermes.
Comparison of monitoring services
| Parameter | Firebase Crashlytics | Sentry |
|---|---|---|
| CLI | firebase-tools | @sentry/cli |
| Hermes compose | manual compose required | automatic support |
| Versioning | via --app and mapping |
mandatory release in SDK and CLI |
| Integration complexity | higher for Hermes | lower – fewer steps |
Sentry setup is 2x faster than Firebase for Hermes projects. Firebase is 3x more popular among Android teams due to its built-in ecosystem. Choose based on your stack.
Common mistakes in deobfuscation
| Mistake | Cause | Solution |
|---|---|---|
| Stack not decoded | Version mismatch | Use a unified format APP_VERSION+BUILD_NUMBER |
| Source map not found | Not uploaded in CI | Add upload step after build |
| Stack references bundle | Hermes without composition | Run compose-source-maps.js |
What is included in the work
We take full responsibility for setup, providing the following deliverables:
- Analysis of current build configuration (Hermes, bundle presence, CI)
- Source map composition scripts for Hermes (if needed) with documentation
- CI integration (GitHub Actions, GitLab CI, Bitrise – any) with access to scripts
- Version format agreement and implementation in SDK
- Verification of deobfuscation with a test crash
- Training session for your team (up to 1 hour)
- Post-setup support for 30 days
We guarantee that after setup, you will receive readable stack traces for every crash. We have done this for more than 50 React Native projects over 5 years. Contact us for an assessment of your project — consultation is free. Get a ready-made solution with automatic source map upload that will reduce debugging time by 70%.
Timelines and cost
Timeline: 4 hours — 2 days depending on current CI setup and Hermes presence. Cost range: $500–$1500 depending on complexity. Write to us — we will assess your project for free. Estimated annual savings: $2,000–$5,000 in developer time.







