Skip to main content

Hermes & HBC

Release builds of a React Native app run Hermes bytecode (HBC), not plain JavaScript. HBC is tied to the Hermes version inside the app binary: bytecode from a different Hermes version won't load.

The rule​

Compile every update with the hermesc from the same react-native install the store build was made from, and change your runtime version whenever you upgrade React Native.

The runtime version is what keeps a bundle away from a binary it can't run: devices only install releases whose runtimeVersion equals their own. With --runtime-version auto, the React Native and Hermes versions are part of the fingerprint, so an upgrade changes it for you. With a fixed string such as rt1, it's on you to move to rt2 in the same commit that upgrades React Native. If an incompatible bundle does get installed, it fails to load, and the crash-loop breaker takes the device back to the last bundle that worked after two failed launches.

How to compile​

dash-ota bundle --hermes runs react-native bundle, then compiles the result with your project's hermesc and replaces the plain bundle:

npx dash-ota bundle --project . --platform android --out ./ota-out/android --hermes
npx dash-ota publish --bundle-dir ./ota-out/android --app-id com.example.app \
--platform android --channel prod --key-id key_prod_1 \
--runtime-version rt1 --bundle-version 8

It finds hermesc in node_modules/react-native/sdks/hermesc/<os>-bin/ (React Native 0.82 and older) or in the hermes-compiler package (0.83 and later). If neither exists, it stops instead of publishing plain JavaScript:

✗ hermesc was not found — cannot produce an HBC bundle. Looked for:

followed by both paths it tried.

Without --hermes the output is a plain JavaScript bundle. That is right for an app that runs on JSC, and wrong for one on Hermes, which is the default.

Keep --out the same for every release. The compiler runs on a relative path, so the same source always produces the same bytes, and the server skips files it already has.

Source maps​

Crashes in an OTA bundle won't symbolicate against the store build's source maps. The CLI doesn't produce source maps, so generate one yourself when you build the bundle (react-native bundle --sourcemap-output, then compose it with the Hermes map as your crash reporter documents) and upload it keyed by runtimeVersion and bundleVersion.