# React Native OTA updates

A React Native app store binary contains two things: compiled native code and
a JavaScript bundle plus its assets. An over-the-air (OTA) update replaces the
JavaScript bundle and assets on a device that already has the binary
installed. The app does not go through the App Store or Google Play again; it
fetches the updated bundle in the background and runs it on the next launch.

This describes the general mechanism, independent of any specific OTA
provider. The final section covers Rollbird's implementation of it.

## What ships over the air

The JavaScript bundle holds your application code: components, screens,
navigation, and business logic, plus any pure-JavaScript dependency. Metro
bundles static assets alongside it — images, fonts, and JSON files the app
reads at runtime.

An OTA update swaps this bundle. The native shell stays exactly as installed:
the compiled iOS and Android binary, the JavaScript engine (Hermes or JSC),
and every native module already linked into it.

Examples of changes that ship over the air: a bug fix in a screen's logic, a
new flow built from native modules already in the binary, a copy or styling
change, an API endpoint change, a new pure-JavaScript dependency.

## What still needs a store submission

Anything that changes the compiled binary needs a new build and a new store
submission. That includes:

- Adding or upgrading a dependency that ships native iOS or Android code, not only JavaScript.
- Upgrading React Native itself.
- Changing native configuration — an `Info.plist` entry, an `AndroidManifest.xml` permission, a native build setting.
- Changing the app's minimum OS version or target SDK.

A native-affecting change usually alters what the installed binary is capable
of running, even when no application code changes. An OTA system that checks
native compatibility before offering an update will not hand that update to a
binary it no longer matches. That check is what keeps a JavaScript bundle
built against one native surface from loading into a binary that does not
have it.

## Channels and staged rollout

A channel is a named target for updates, embedded in the binary at build
time. A common setup uses one channel for internal or preview builds and
another for the build distributed to end users. Publishing to one channel
does not reach binaries built for another — only a binary carrying that
channel requests it.

Staged rollout limits a new update to a percentage of eligible devices
instead of all of them at once. Publishing at a low percentage first, then
watching crash and error rates before raising it, catches a bad release
before it reaches your full install base.

## Rollback

Rollback reverts a channel to its previous working release without
publishing a new one and without a store review. Because the update itself
is a JavaScript bundle rather than a new binary, undoing it is a change to
which release a channel serves, not a new build.

A rollback targets a release that is already live and already causing a
problem, not one still being decided. Because the problem already exists in
production, rollback needs to operate independently of the limits that gate
a new release — a quota, a storage cap, a billing status.

## How Rollbird does it

Rollbird is a hosted OTA update service for React Native and Expo apps.
`rollbird init --channel preview` links a project, provisions a signing key,
and embeds a channel into your native build. `rollbird release` bundles,
signs, and publishes your JavaScript bundle to that channel. `rollbird
rollback` reverts a channel to its previous release — instantly, at no cost,
and regardless of plan or quota.

The [getting-started guide](https://rollbird.dev/docs/getting-started/) walks
through the full path, from installation to a verified preview update and a
tested rollback. The [React Native SDK guide](https://rollbird.dev/docs/react-native/)
covers the wrapper, channels, compatibility strategies, and Expo
configuration in more depth.

Rollbird's plans scale with apps, storage, seats, and release history, never
with end users or monthly active users. See
[pricing](https://rollbird.dev/#pricing) for current plans.
