Uploading Source Maps to Bugsnag | Stallion OTA Updates
Learn how to upload React Native source maps from Stallion OTA updates to Bugsnag for accurate error monitoring. Complete guide for Hermes and JavaScript Core builds, including source map composition, code bundle ID configuration, and Bugsnag integration with Stallion for production debugging.
CLI Requirement:
Source map upload to Bugsnag requires Stallion CLI version 2.4.0 or above. Make sure you're running the latest version. Check the CLI Installation guide if you need to update.
Publish Bundle
When publishing with --keep-artifacts=true and --sourcemap=true, Stallion performs the standard OTA publish flow and additionally persists all bundle and sourcemap outputs on disk for Bugsnag integration.
Example command:
stallion publish-bundle --upload-path=orgname/project-name/bucket-name --platform=android/ios --release-note="notes" --keep-artifacts=true --sourcemap=true
This enables deterministic Bugsnag integration without re-running any React Native bundling step.
-
Normal OTA publish is executed
Stallion generates the platform bundles, applies Hermes compilation when enabled, uploads the OTA payload to the Stallion backend, and completes the rollout exactly as in a standard publish.
-
Source maps are generated
With
--sourcemap=true, Stallion ensures both standard JS sourcemaps and Hermes sourcemaps are produced for the publish.Instead of treating the bundle and sourcemap as temporary files, Stallion keeps the final outputs in a stable directory structure so you can reliably pick them up in CI and upload to Bugsnag.
-
Artifacts are persisted on disk
With
--keep-artifacts=true, Stallion does not delete any intermediate build outputs and writes the final bundle + sourcemap pairs into a stable, CI-friendly directory.The resulting structure is:
stallion-artifacts/ ├── android/ │ ├── normal/ │ │ ├── index.android.bundle │ │ └── index.android.bundle.map │ └── hermes/ │ ├── index.android.bundle │ └── index.android.bundle.hbc.map └── ios/ ├── normal/ | ├── main.jsbundle | └── main.jsbundle.map └── hermes/ ├── main.jsbundle └── main.jsbundle.hbc.map
Prepare sourcemaps for Bugsnag
Javascript Core
You can upload normal JS sourcemap directly to Bugsnag. No additional steps are required.
Hermes
For Hermes builds, you need to compose the packager and Hermes sourcemaps. Use the following commands:
mv stallion-artifacts/android/normal/index.android.bundle.map stallion-artifacts/android/normal/index.android.bundle.packager.map
node \
node_modules/react-native/scripts/compose-source-maps.js \
stallion-artifacts/android/normal/index.android.bundle.packager.map \
stallion-artifacts/android/hermes/index.android.bundle.hbc.map \
-o stallion-artifacts/android/normal/index.android.bundle.map
rm -f stallion-artifacts/android/normal/index.android.bundle.packager.map
Upload to Bugsnag
Installation
Install the Bugsnag source maps uploader:
npm install --save-dev @bugsnag/source-maps
# or
yarn add --dev @bugsnag/source-maps
Extract Bundle Hash
When publishing a bundle, extract the bundle hash from the output. In your CI pipeline:
OUTPUT=$(stallion publish-bundle \
--upload-path=$UPLOAD_PATH \
--platform=$PLATFORM \
--release-note="$RELEASE_NOTE" \
--keep-artifacts=true \
--sourcemap=true)
BUNDLE_HASH=$(echo "$OUTPUT" | grep -oE '[a-f0-9]{64}')
CODE_BUNDLE_ID=${BUNDLE_HASH:0:32} # First 32 characters
The CODE_BUNDLE_ID (first 32 characters of the bundle hash) is used to associate source maps with the running bundle, similar to how CodePush uses bundle identifiers.
Upload Source Maps
Upload the bundle and source map to Bugsnag using the code bundle ID:
Javascript Core
Upload source maps for React Native JavaScript Core application.
npx bugsnag-source-maps upload-react-native \
--api-key YOUR_API_KEY_HERE \
--code-bundle-id $CODE_BUNDLE_ID \
--platform android \
--source-map stallion-artifacts/android/normal/index.android.bundle.map \
--bundle stallion-artifacts/android/normal/index.android.bundle
Hermes
Upload source maps for React Native Hermes applications.
npx bugsnag-source-maps upload-react-native \
--api-key YOUR_API_KEY_HERE \
--code-bundle-id $CODE_BUNDLE_ID \
--platform android \
--source-map stallion-artifacts/android/normal/index.android.bundle.map \
--bundle stallion-artifacts/android/hermes/index.android.bundle
Configure Bugsnag in Your App
In your React Native app, configure Bugsnag to use the code bundle ID from the currently running Stallion bundle:
import Bugsnag from '@bugsnag/react-native';
import { useStallionUpdate } from 'react-native-stallion';
// Get the current bundle ID from Stallion
const { currentlyRunningBundle } = useStallionUpdate();
Bugsnag.start({
codeBundleId: currentlyRunningBundle?.id, // First 32 chars of bundle hash
// ... other Bugsnag configuration
});
The currentlyRunningBundle.id from Stallion SDK matches the first 32 characters of the bundle hash, which is the same CODE_BUNDLE_ID used when uploading source maps. This ensures Bugsnag can correctly associate stack traces with the uploaded source maps.
Complete CI Example
Here's a complete GitHub Actions example that publishes, extracts the hash, and uploads to Bugsnag:
- name: Publish Bundle and Extract Hash
id: publish
run: |
echo "Publishing bundle..."
OUTPUT=$(stallion publish-bundle \
--upload-path=$UPLOAD_PATH \
--platform=$PLATFORM \
--release-note="$RELEASE_NOTE" \
--keep-artifacts=true \
--sourcemap=true)
echo "$OUTPUT"
BUNDLE_HASH=$(echo "$OUTPUT" | grep -oE '[a-f0-9]{64}')
CODE_BUNDLE_ID=${BUNDLE_HASH:0:32}
echo "Bundle hash: $BUNDLE_HASH"
echo "Code bundle ID: $CODE_BUNDLE_ID"
echo "BUNDLE_HASH=$BUNDLE_HASH" >> $GITHUB_ENV
echo "CODE_BUNDLE_ID=$CODE_BUNDLE_ID" >> $GITHUB_ENV
- name: Prepare Hermes Source Maps (if using Hermes)
run: |
if [ "$PLATFORM" = "android" ]; then
mv stallion-artifacts/android/normal/index.android.bundle.map stallion-artifacts/android/normal/index.android.bundle.packager.map
node node_modules/react-native/scripts/compose-source-maps.js \
stallion-artifacts/android/normal/index.android.bundle.packager.map \
stallion-artifacts/android/hermes/index.android.bundle.hbc.map \
-o stallion-artifacts/android/normal/index.android.bundle.map
rm -f stallion-artifacts/android/normal/index.android.bundle.packager.map
else
mv stallion-artifacts/ios/normal/main.jsbundle.map stallion-artifacts/ios/normal/main.jsbundle.packager.map
node node_modules/react-native/scripts/compose-source-maps.js \
stallion-artifacts/ios/normal/main.jsbundle.packager.map \
stallion-artifacts/ios/hermes/main.jsbundle.hbc.map \
-o stallion-artifacts/ios/normal/main.jsbundle.map
rm -f stallion-artifacts/ios/normal/main.jsbundle.packager.map
fi
- name: Upload Source Maps to Bugsnag
run: |
if [ "$PLATFORM" = "android" ]; then
npx bugsnag-source-maps upload-react-native \
--api-key $BUGSNAG_API_KEY \
--code-bundle-id $CODE_BUNDLE_ID \
--platform android \
--source-map stallion-artifacts/android/normal/index.android.bundle.map \
--bundle stallion-artifacts/android/hermes/index.android.bundle
else
npx bugsnag-source-maps upload-react-native \
--api-key $BUGSNAG_API_KEY \
--code-bundle-id $CODE_BUNDLE_ID \
--platform ios \
--source-map stallion-artifacts/ios/normal/main.jsbundle.map \
--bundle stallion-artifacts/ios/hermes/main.jsbundle
fi
- name: Release Bundle
run: |
stallion release-bundle \
--project-id=$PROJECT_ID \
--hash=$BUNDLE_HASH \
--app-version=$APP_VERSION \
--release-note="$RELEASE_NOTE" \
--ci-token=$CI_TOKEN