skip to content

OTA Updates

EAS Update ships new JavaScript and assets to installed apps through channels and branches, guarded by runtime versions. Interviewers ask what can ship over the air and what needs a store release.

part ofExpo (React Native)overview, primer and where to startread it →
on this pageshow

explore

questions

18

With EAS Update, how do you ship a typo fix to production over the air, and what do --channel, --branch and --message do?

level: juniorimportance: must knowfreq 50%

answer

  1. JavaScript and assets only
  2. --channel follows the current mapping
  3. --branch writes to a named branch
  4. --message labels the update
  5. --environment on SDK 55 and later

basics

~20 s

Fix the text, then run eas update --channel production --environment production --message "Fix typo". EAS bundles the JavaScript, uploads it to the branch production points at, and compatible production builds download it on a later launch.

solid answer

~40 s

A typo is JavaScript, so it can ship over the air; anything touching native code cannot. After fixing it, run `eas update --channel production --environment production --message "Fix checkout typo"`. `eas update` bundles the app (all platforms by default) and uploads an update group. `--channel production` publishes to **whichever branch the production channel points at**, creating and linking a same-name branch if needed. `--branch <name>` instead writes to that branch regardless of mapping, so it reaches users only if a channel follows it. `--message` (`-m`) labels the update in history; `--auto` fills branch and message from the current Git branch and last commit. On SDK 55 and later, `--environment` selects the EAS environment variables used to bundle. Production builds with the same runtime version pick it up on a later launch.

code

bash · 5 lines
bash
# publish the fix to whatever branch the production channel follows
eas update --channel production --environment production --message "Fix typo on checkout screen"

# check what production builds will now receive
eas channel:view production

go deeper

for a junior

Recall that JavaScript and asset fixes can ship over the air with eas update, while native changes need a new build.

for a middle

Explain how --channel resolves to a branch, why --branch can publish to a branch nobody follows, and what --message and --environment add.

for a senior

Show a disciplined hotfix path: same environment as the build, staging first, then promote the tested update rather than re-exporting.

for a principal

Decide what the team allows over the air without review, who may publish to production, and how hotfixes are recorded.

## What can ship over the air **EAS Update** replaces the **update layer** of an app: the JavaScript bundle and the assets it references. A typo in a `<Text>` string, a wrong colour or a logic bug in a component all live there. Anything in the **native layer** — a new native module, a permission, an SDK upgrade, a change to app config that prebuild turns into native code — needs a new binary. The typo fix is the textbook OTA case. ## Publishing the fix The command: ```bash eas update --channel production --environment production --message "Fix typo on checkout screen" ``` What happens: 1. EAS CLI **exports** the project with the bundler into the `dist` directory, by default for all platforms (`--platform android` or `ios` narrows it). 2. It uploads the bundle and assets as an **update group** — one update per platform — with the **runtime version** from app config. 3. The group becomes the newest update on the target **branch**. 4. Builds whose channel follows that branch, with a matching runtime version and platform, get it the next time `expo-updates` checks, which by default is at launch. ## --channel versus --branch | Flag | Where the update goes | Typical use | |---|---|---| | `--channel production` | the branch the `production` channel currently points at | hotfixes when you think in channels | | `--branch production` | the branch named `production`, whatever points at it | branch-based flows, previews, version branches | | `--auto` | branch = current Git branch, message = last commit | Git-driven automation | Details worth knowing: - `--channel` looks the mapping up on the server. If the channel does not exist, or exists without a branch, EAS CLI creates a branch with the channel's name and links it. - If the channel is mid-rollout between two branches, `--channel` refuses and asks for `--branch`. - `--branch` never changes any mapping. Publishing to a branch no channel follows is safe for testing and invisible to users. - You cannot pass both `--channel` and `--branch`. ## --message and --environment - **`--message`** (`-m`) is a short description stored with the update and shown by `eas branch:view`, `eas update:view` and the dashboard. In `--non-interactive` mode EAS CLI requires `--message` together with `--branch` or `--channel`, unless `--auto` supplies both. - **`--environment`** names the EAS environment (`production`, `preview`, `development`) whose server-side environment variables are used while bundling. EAS CLI's help marks it as required for projects on Expo SDK 55 or later, which includes SDK 57. Use the same environment the production build used, so values baked into the bundle match. ## When users see it The update is available at once, but users see it only after the app downloads it. With default settings, `expo-updates` checks on launch; if the download finishes quickly the new bundle runs, otherwise it runs on the following launch. A typo fix therefore reaches most active users within a launch or two, without a store review. ## Recording and checking the hotfix - Write a message someone can search later, such as the ticket and screen; `eas branch:view` and the dashboard show it next to the runtime version. - In CI, `--auto` uses the current Git branch as the EAS branch and the last commit message as the message, which ties updates to commits without extra flags. - Publish for one platform with `--platform ios` or `--platform android` only when the fix really is platform-specific; otherwise the default of all platforms keeps both apps in step. - After publishing, `eas channel:view production` confirms which branch production follows and which update is now newest on it. ## A safer variant If the team has a staging build with the same runtime version, publish the fix to `--channel staging` first, verify it, then promote the **same** update to production with `eas update:republish --destination-channel production`, so production receives exactly the bundle that was tested rather than a fresh export. ## Common mistakes - Publishing with `--branch fix-typo` and wondering why nobody got it: no channel follows that branch. - Expecting the update on an older store version whose runtime version differs. - Shipping a change that also needs native code, and crashing on old binaries — the runtime version exists to prevent exactly that.

  • Why would eas update --channel production fail with a message telling you to use --branch?
    The production channel is currently mapped to two branches because a branch-based rollout is in progress. EAS CLI cannot tell which branch to publish to, so it asks for an explicit `--branch`.
  • Which parts of a fix mean it cannot ship as an EAS Update?
    Anything in the native layer: adding or upgrading a native module, changing permissions or entitlements, or config that prebuild turns into native code. Those need a new build with a new runtime version; EAS Update only replaces JavaScript and assets.

saying these in an interview costs you the question

  • eas update --branch hotfix reaches production users automatically
  • An OTA update can add a new native module
  • --message chooses which builds receive the update
  • Publishing requires a store review before users receive it
  • --channel and --branch can be combined to target both
open as a page

In an Expo app using expo-updates, why do users usually see a newly published EAS Update only on their second launch?

level: juniorimportance: must knowfreq 62%

basics

~20 s

By default expo-updates checks on every cold launch (checkAutomatically: ON_LOAD) but waits 0 ms for the result (fallbackToCacheTimeout: 0), so the app starts on its current bundle, downloads the update in the background and runs it on the next cold start.

open as a page

In an Expo app shipping EAS Update, what does runtimeVersion guarantee, and which changes force a new runtime version and a new build?

level: juniorimportance: must knowfreq 44%

basics

~20 s

runtimeVersion labels the native layer a build contains; EAS Update serves an update only to builds whose runtime version and platform match exactly. Any change to native code or native config needs a new build and a new runtime version.

open as a page

In EAS Update, what is the difference between a channel and a branch, and how does an installed build decide which update to run?

level: middleimportance: must knowfreq 55%

basics

~20 s

A channel is a name compiled into a build; a branch is an ordered list of published updates. Each channel points at a branch, and a build runs that branch's newest update matching its runtime version and platform.

open as a page

With expo-updates, how would you let a news app download an update mid-session and prompt readers to restart into it?

level: middleimportance: must knowfreq 48%

basics

~20 s

Call Updates.checkForUpdateAsync() at a sensible moment, then fetchUpdateAsync() if isAvailable is true; when useUpdates() reports isUpdatePending, show a restart prompt whose button calls Updates.reloadAsync(). If the reader declines, the update runs on the next cold start.

open as a page

In EAS Update, how do you publish an update to 10% of users, then widen or finish that rollout?

level: middleimportance: must knowfreq 45%

basics

~20 s

Publish with eas update --rollout-percentage 10, so only that share of devices gets the update and the rest keep the previous one. Raise it with eas update:edit, then end it by setting 100 or by running eas update:revert-update-rollout.

open as a page

What does eas update:rollback do in EAS Update, and when does it roll back to the embedded update instead of a published one?

level: middleimportance: must knowfreq 46%

basics

~20 s

eas update:rollback undoes the latest update on a branch by publishing again: it republishes the update group before it, or, when none exists for that branch and runtime version, publishes a roll-back-to-embedded directive that returns clients to the bundle inside their binary.

open as a page

In EAS Update, how do you promote an update tested on staging to production, and when would you use eas channel:edit versus eas update:republish?

level: middleimportance: should knowfreq 40%

basics

~10 s

Either repoint the production channel at the tested branch with eas channel:edit, or copy the tested update group onto production's branch with eas update:republish --destination-channel production. Both reuse the tested bundle without rebuilding.

open as a page

In an Expo app config, how do the appVersion, nativeVersion and fingerprint runtimeVersion policies differ, and when would you set a plain string instead?

level: middleimportance: should knowfreq 30%

basics

~10 s

appVersion copies the app version, nativeVersion adds the build number, and fingerprint hashes native-affecting project inputs. A plain string gives full manual control and, besides fingerprint, is the only option in a bare project.

open as a page

An EAS Update hotfix published from CI makes production builds call the staging API; what does eas update's --environment flag change, and how do you prevent this?

level: seniorimportance: should knowfreq 30%

basics

~20 s

An API URL read at bundle time is baked into the update. --environment production makes eas update bundle with that EAS environment's variables and ignore local .env files; a CI job without it uses the runner's values.

open as a page

An EAS Update you published crashes at launch; what does expo-updates do on devices that downloaded it, and what should you do next?

level: seniorimportance: should knowfreq 42%

basics

~20 s

expo-updates' error recovery catches early fatal JS errors. If the update never rendered, it is marked failed and the app falls back to the last working update unless a newer one arrives within 5 s; once it has rendered, recovery only fetches a fix, then crashes.

open as a page

An EAS Update at a 10% rollout is crashing for some users; how do you revert it, and what happens to devices that already downloaded it?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Run eas update:revert-update-rollout: it deletes the rollout group and republishes the control update the other 90% run. Devices holding the bad update pick up that newer copy on their next check; if the branch had no earlier update, the revert publishes a roll back to embedded instead.

open as a page

An Expo app on the appVersion runtimeVersion policy adds a native camera module, the team publishes an EAS Update without bumping version, and 1.4.0 users crash at launch: what went wrong, and how do you prevent it?

level: seniorimportance: should knowfreq 28%

basics

~20 s

appVersion still resolved to 1.4.0, so EAS served the update to 1.4.0 binaries that lack the camera's native code, and its import threw at launch. Ship native changes in a new build with a new runtime version.

open as a page

As the lead of a team adopting EAS Update, what would you allow to ship over the air, and which EAS guardrails would you require?

level: principalimportance: should knowfreq 28%

basics

~20 s

Allow JavaScript and asset fixes and small flag-guarded features within the current runtime version; send native and large product changes through store builds. Require per-update rollouts, a rehearsed revert and rollback, code signing where tampering matters, and traceable publishes.

open as a page

How do you preview a published EAS Update inside an Expo development build before any production channel points at it?

level: middleimportance: nice to knowfreq 25%

basics

~20 s

Publish the change to a branch no production channel follows, then open a development build that includes expo-updates, sign in on its Extensions tab and open the update from that branch; it must match the build's runtime version.

open as a page

In expo-updates, what distinguishes isEmbeddedLaunch from isEmergencyLaunch, and what should an app do when each is true?

level: middleimportance: nice to knowfreq 18%

basics

~20 s

isEmbeddedLaunch is true when the running update is the one compiled into the binary, a normal state after install. isEmergencyLaunch is true when expo-updates hit an error at startup and fell back to the embedded bundle; log emergencyLaunchReason and tolerate older persisted data.

open as a page

How does EAS Update code signing prove an update came from you, and why does adding or rotating its certificate need a new runtime version?

level: seniorimportance: nice to knowfreq 20%

basics

~20 s

You generate a key pair and certificate with npx expo-updates codesigning:generate, embed the certificate in builds via updates.codeSigningCertificate, and sign each update locally with the private key; expo-updates verifies the signature before applying and rejects a missing or invalid one.

open as a page

With Expo's fingerprint runtimeVersion policy, what does @expo/fingerprint hash, and why can the runtime version change unexpectedly or fail to change when it should?

level: seniorimportance: nice to knowfreq 16%

basics

~20 s

@expo/fingerprint hashes, per platform, the app config, config plugins, autolinked native packages and any committed native folders, not app JavaScript. Version bumps or dynamic config change it unexpectedly; edits inside inline plugin mods and ignored paths escape it.

open as a page