You ship a release, and an hour later a crash report comes in: a typo in an API URL breaks checkout. Without OTA updates, you'd wait a day or more for app review. With EAS Update, the fix reaches users on their next app launch, usually within minutes.
How OTA updates work
An Expo app has two layers:
- Native code (the binary): Expo SDK modules, native libraries, permissions, and the icon. This changes only with a new store build.
- The JavaScript bundle and assets: your screens, logic, styles, and images.
EAS Update replaces the second layer. Each build has a runtime version that identifies its native code, and an update is only delivered to builds with a matching runtime version, so you never ship JavaScript that calls native code the build doesn't have.
1. Set up
npm install -g eas-cli
npx expo install expo-updates
eas update:configure
eas update:configure adds runtimeVersion and updates.url to your app config, and sets a channel on your build profiles in eas.json:
{
"build": {
"preview": { "channel": "preview", "distribution": "internal" },
"production": { "channel": "production" }
}
}
A channel is baked into each build. Production builds listen to production, and internal test builds listen to preview.
2. Choose a runtime version policy
The runtime version decides which builds can receive which updates:
{
"expo": {
"runtimeVersion": { "policy": "fingerprint" }
}
}
fingerprintis computed from your native dependencies and config. It changes automatically when native code changes, which makes it the safest default. (In SDK 58 the default fingerprint preset isbalanced, so app version bumps no longer change it.)appVersionuses yourversionfield. It's simple, but you must remember to bump it when native code changes.
3. Build, then publish updates
Create builds once:
eas build --profile production --platform all
After that, ship JavaScript changes with:
eas update --channel production --environment production --message "Fix checkout API URL"
The --environment flag is required on SDK 55+. It selects which EAS environment variables are baked into the update.
4. Roll out gradually
Never send an update to 100% of users at once. Start small:
eas update --channel production --environment production --message "New onboarding copy" --rollout-percentage=10
Watch crash and error rates (for example in Expo Observe), then increase the percentage:
eas update:edit
If something's wrong, revert:
eas update:revert-update-rollout
For larger changes, eas channel:rollout performs a branch-based rollout between two branches of updates.
5. Check for updates in the app
By default, apps check for updates on launch and apply them on the next launch. You can also prompt users with the useUpdates hook:
import * as Updates from "expo-updates"
import { Button, Text, View } from "react-native"
export function UpdateBanner() {
const { isUpdateAvailable, isUpdatePending } = Updates.useUpdates()
if (isUpdatePending) {
return <Button title="Restart to update" onPress={() => Updates.reloadAsync()} />
}
if (isUpdateAvailable) {
return <Button title="Download update" onPress={() => Updates.fetchUpdateAsync()} />
}
return null
}
Call Updates.checkForUpdateAsync() when the app returns to the foreground if you want users to get fixes faster.
What you can and can't ship over the air
Can ship OTA:
- Bug fixes in JavaScript or TypeScript
- UI and copy changes, styling, and images
- New screens built only from existing native modules
- Feature flags and config changes
Needs a new store build:
- Adding or upgrading a native module (for example MMKV or expo-widgets)
- Changing permissions, icons, splash screens, or config plugins
- Upgrading the Expo SDK (SDK 58 upgrade guide)
Best practices
- Use the fingerprint policy so incompatible updates can't be delivered.
- Test on
previewfirst with an internal build, then publish toproduction. - Always do staged rollouts and watch error rates.
- Write useful messages. They're your changelog when debugging.
- Respect store rules. Use OTA for fixes and iterations, not for shipping a different app.
- Automate it with EAS Workflows or CI on merge to
main.
Next steps
OTA updates handle the after-launch part. For the first release, follow our guide to publishing an Expo app to the App Store and Google Play. Starting a new app? Our Expo templates are ready for EAS Build and EAS Update from day one.