React Native and Expo source maps

Using our source map library you can upload source maps to unminify stack traces and get human-readable method names, files, and line numbers.

To configure your project to upload source maps and native mappings automatically, follow the showing full stacktraces guide for React Native.

The guide on this page shows how to upload source maps on-demand, which is useful when:

  • You’re using CodePush or Expo EAS Update
  • You want to test out source maps in development

We are in the process of developing a general-purpose BugSnag CLI for performing uploads across our supported platforms. For apps that follow a standard project layout, the upload command locates the appropriate files and version information to send to BugSnag.

The BugSnag CLI can be used in place of the bugsnag-source-maps package described below. See our upload instructions for details.

Installation

@bugsnag/source-maps provides a CLI and a JavaScript library that can be used to upload your application’s source maps.

Install it globally on your system:

npm install --global @bugsnag/source-maps
# or
yarn global add @bugsnag/source-maps

Or locally inside your project:

npm install --save-dev @bugsnag/source-maps
# or
yarn add --dev @bugsnag/source-maps

Usage

The library can be used via the command line:

bugsnag-source-maps upload-react-native <opts>

Or as a JavaScript API:

const { reactNative } = require('@bugsnag/source-maps')

interface reactNative  {
  async function uploadOne (UploadSingleOpts): Promise<void>
  async function fetchAndUploadOne (FetchUploadOpts): Promise<void>
}

React Native

In addition to standard bundles, the Random Access Modules (RAM) bundle format is also supported. Delta bundles used in dev mode are not supported. They can be disabled via the in-app developer menu.

Development

To upload React Native source maps in a development environment, you can use the @bugsnag/source-maps CLI. This command will fetch the source map and bundle from the React Native bundle server (Metro).

bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --fetch \
  --dev \
  --platform ios \
  --app-version YOUR_APP_VERSION
  --app-bundle-version YOUR_APP_BUNDLE_VERSION \
bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --fetch \
  --dev \
  --platform android \
  --app-version YOUR_APP_VERSION
  --app-version-code YOUR_APP_VERSION_CODE \

If you’re running Metro somewhere other than the default (http://localhost:8081), or your app’s entry point is not index.js, you can provide these to the command using the --bundler-url and --bundler-entry-point arguments.

Release

If Hermes is enabled, see the Hermes example.

If you’re using App Center CodePush, see the CodePush example.

The source maps used for the release variant can be generated via the react-native bundle (or react-native ram-bundle) command.

react-native bundle \
  --dev false \
  --entry-file index.js \
  --platform ios \
  --sourcemap-output ios-release.bundle.map \
  --bundle-output ios-release.bundle
react-native bundle \
  --dev false \
  --entry-file index.js \
  --platform android \
  --sourcemap-output android-release.bundle.map \
  --bundle-output android-release.bundle

The generated source map and bundle file can then be uploaded with the CLI:

bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --app-version YOUR_APP_VERSION \
  --app-bundle-version YOUR_APP_BUNDLE_VERSION \
  --platform ios \
  --source-map ios-release.bundle.map \
  --bundle ios-release.bundle
bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --app-version YOUR_APP_VERSION \
  --app-version-code YOUR_APP_VERSION_CODE \
  --platform android \
  --source-map android-release.bundle.map \
  --bundle android-release.bundle

Hermes

If you’re using CodePush and Hermes together, refer to the CodePush section instead.

If you are using Hermes, you can use the standard instructions above for development builds.

Android

For a release build, the bundle and source map are built as part of the Gradle build and are output in a different location.

First, build the app’s release variant:

cd android && ./gradlew assembleRelease

Then, use the CLI to upload the bundle and source map from their generated locations inside android/app/build/...

bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --app-version 1.2.3 \
  --platform android \
  --source-map android/app/build/generated/sourcemaps/react/release/index.android.bundle.map \
  --bundle android/app/build/generated/assets/react/release/index.android.bundle

You must specify at least one (or both) of --app-version or --app-version-code.

iOS

On iOS, source maps are not created automatically. To obtain and upload source maps for a build, the build must be updated to generate source maps. The upload command can then retrieve them from the generated location.

To update the build, open the Bundle React native code and images Xcode build phase and add the following. This will ensure source maps are generated.

The provided example generates the source map in a temporary folder, rather in the build directory, so it doesn’t get included in the package and unnecessarily increase its footprint.

+ export EXTRA_PACKAGER_ARGS="--sourcemap-output $TMPDIR/$(md5 -qs "$CONFIGURATION_BUILD_DIR")-main.jsbundle.map"
set -e

export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.sh

After a successful build, using xcodebuild you can find the location Xcode has placed the assets. Invoke it from your project directory, replacing the <YOUR_PROJECT_NAME> placeholders with your project name:

xcodebuild -workspace ios/<YOUR_PROJECT_NAME>.xcworkspace -scheme <YOUR_PROJECT_NAME> -showBuildSettings | grep CONFIGURATION_BUILD_DIR

Then, use the CLI to upload the bundle and source map from their generated locations:

export CONFIGURATION_BUILD_DIR='' # use result from previous step
bugsnag-source-maps upload-react-native \
  --api-key YOUR_API_KEY_HERE \
  --app-version 1.2.3 \
  --platform ios \
  --source-map $TMPDIR/$(md5 -qs "$CONFIGURATION_BUILD_DIR")-main.jsbundle.map \
  --bundle $CONFIGURATION_BUILD_DIR/main.jsbundle

CodePush

If you’re using CodePush and Hermes together, you’ll need to use appcenter-cli v2.10.0+ to ensure source maps are produced correctly.

When you release an update for your app using App Center CodePush, specify both --output-dir and --sourcemap-output in order to capture the source map and asset bundle files for upload.

appcenter codepush release-react \
    --app <ownerName>/<appName> \
    --output-dir build \
    --sourcemap-output build

Upload the source map, specifying the code bundle identifier instead of the app version/app version code.

bugsnag-source-maps upload-react-native \
    --api-key YOUR_API_KEY_HERE \
    --code-bundle-id 1.0.0-b12 \
    --platform ios \
    --source-map build/CodePush/main.jsbundle.map \
    --bundle build/CodePush/main.jsbundle
bugsnag-source-maps upload-react-native \
    --api-key YOUR_API_KEY_HERE \
    --code-bundle-id 1.0.0-b12 \
    --platform android \
    --source-map build/CodePush/index.android.bundle.map \
    --bundle build/CodePush/index.android.bundle

Expo

It is not currently possible to manually upload source maps when building your app using EAS Build. Instead we recommend following the showing full stacktraces guide for Expo to upload source maps automatically.

EAS Update

When you publish an update for your app using EAS Update, make a note of the Group ID for the update.

Upload the source map, specifying the Update Group ID as the code bundle identifier instead of the app version/app version code:

bugsnag-source-maps upload-react-native \
    --api-key YOUR_API_KEY_HERE \
    --code-bundle-id ef264aeb-0712-4273-98d6-119a0efd6acd \
    --platform ios \
    --source-map dist/bundles/ios-c8a64d43ec5c4ede9121fdb4098a2b44.map \
    --bundle dist/bundles/ios-c8a64d43ec5c4ede9121fdb4098a2b44.js
bugsnag-source-maps upload-react-native \
    --api-key YOUR_API_KEY_HERE \
    --code-bundle-id ef264aeb-0712-4273-98d6-119a0efd6acd \
    --platform android \
    --source-map dist/bundles/android-b50801f94c3c41deaa824bcdfec44b4e.map \
    --bundle dist/bundles/android-b50801f94c3c41deaa824bcdfec44b4e.js

Option reference

The full set of options for @bugsnag/source-maps.

Property (CLI, JS API) Type Description
--api-key,
apiKey
string your project’s API key [required]
--app-version,
appVersion
string the version of the application you are building (this should match the appVersion configured in your notifier).
--code-bundle-id,
codeBundleId
string for apps deployed with CodePush or EAS Update. Correlates to a Code Push or Expo EAS Update bundle ID
--app-version-code,
appVersionCode
string Android-only app version
--app-bundle-version,
appBundleVersion
string iOS-only app version
--dev,
dev
boolean indicates this is a debug build
--endpoint,
endpoint
string customize the endpoint for BugSnag On-Premise
--idle-timeout,
idleTimeout
number idle timeout for HTTP requests in minutes (see the Node request.setTimeout docs)
logger
(JS only)
Object provide a custom logger (must match the internal Logger interface)
--no-overwrite,
overwrite
boolean whether to replace existing source maps uploaded with the same version (defaults to overwrite=true for React Native uploads – to set overwrite=false from the CLI use the --no-overwrite flag)
--platform,
platform
string the application platform, either “android” or “ios” [required]
--project-root,
projectRoot
string the top level directory of your project
requestOpts
(JS only)
RequestOptions Supply options that should be passed to http.request(), for example if you need to provide an agent to send via a proxy.
--quiet
(CLI only)
boolean less verbose logging
Single upload options
--source-map,
sourceMap
string the path to the source map [required]
--bundle,
bundle
string the path to the bundle [required]
Fetch upload options
--fetch,
fetch
boolean enable fetch mode [required]
--bundler-url,
bundlerUrl
string the URL of the React Native bundle server
--bundler-entry-point,
bundlerEntryPoint
string the entry point of your React Native app