What you can and can't ship over the air in React Native
OTA updates cover your JavaScript, assets, and most product logic — but not native code. Here is the exact boundary, so you know when a change needs a new native build.
Over-the-air updates feel like magic until the first time a change refuses to ship and you cannot work out why. The confusion almost always comes from one boundary: what lives in the native binary versus what lives in the JavaScript bundle. Get that model right and OTA becomes predictable.
The mental model
An installed app is two things stapled together: a native binary — your Swift and Kotlin code, native modules, and the Hermes engine — and a JavaScript bundle that the binary loads at startup. An OTA update replaces the JavaScript bundle and its assets. It cannot change the native binary, because that binary is what the store reviewed and signed.
Ships over the air
- React components, screens, and navigation logic.
- Business logic and bug fixes written in JavaScript or TypeScript.
- Copy, text, and localization strings.
- Styles and layout.
- Bundled assets: images, fonts, JSON, and other files packaged with the bundle.
- Feature flags and remote configuration handled in JS.
- Most pure-JavaScript third-party libraries.
Needs a new native build and store submission
- Adding or upgrading a native module (anything with iOS or Android code).
- Changing native permissions,
Info.plist, orAndroidManifest.xml. - App icon, splash screen, or bundle identifier changes.
- Upgrading the React Native or Hermes version.
- New native dependencies of any kind.
The gotchas
The boundary has two sharp edges. First, if a JavaScript update calls a native capability that is not present in the installed binary, it will crash at runtime. That is why updates are matched to an app version: you target a JS bundle at the native build that can actually run it. Second, a JS bundle compiled against one Hermes version can fail to load on a binary built with a different one — keep your build environment aligned with your release binary. If you are on the New Architecture, validate the full update lifecycle against your exact configuration. React Native made the New Architecture the default in 0.76, while classic CodePush is archived; we cover the migration risk in our CodePush compatibility guide.
The practical rule
If a change only touches your JavaScript or TypeScript and bundled assets, and adds no native dependency, it is generally compatible with an OTA update. If it touches anything native, it needs a new build. This technical line is not the same as the policy line: store compliance also depends on what the update changes and how the app was represented in review. See the policy guardrailsbefore treating a compatible change as publishable.