Skip to main content

Over-the-air updates

expo-updates lets the app download new JavaScript and assets at launch without a store release. It checks https://u.expo.dev/<projectId> on every launch (checkAutomatically: ALWAYS, fallbackToCacheTimeout: 0), so a published update is picked up on the next cold start after download.

Channels and runtime versions​

Build profileChannel
developmentdevelopment
previewpreview
productionproduction

runtimeVersion.policy is appVersion: an update only applies to builds with the same version in app.json. After npm run version and a new store build, updates must be published for the new version; older installs keep receiving updates for theirs until you stop publishing them.

eas update --channel production --message "Fix verse finder empty state"
eas update --channel preview --message "..."

What can and cannot go OTA​

ChangeOTA?
JavaScript, styles, locales, curriculum JSON, Bible metadata JSONyes
New or upgraded native module, config plugin, permission, Google client id, splash/iconno: native build and store release
Backend API changeyes for the app side, but deploy the backend first and keep it compatible with the previous app version

The mobile CLAUDE.md says Google sign-in "needs a new dev-client / EAS build, not just an OTA update"; the same applies to anything listed in the second row.

Checking what users have​

eas update:list --channel production shows published updates; eas build:list shows builds and their runtime versions. The app's Constants.expoConfig is read in App.js but not surfaced; adding the update id to Settings would help support.

Rolling back​

Publish the previous good commit as a new update (eas update --channel production from that commit), or eas update:republish. Users get it on their next launch.