Managing App Updates with Expo Over-The-Air (OTA) Delivery
Stop waiting for app store reviews for every bug fix. Learn how Expo's OTA updates deliver JavaScript changes instantly and where the native code boundary lies.
03 Aug 2025, 08:33 UTC

The problem: The app store review bottleneck
When a critical UI bug or a logic error hits production in a React Native app, the standard fix involves updating the code, incrementing the build version, and submitting a new binary to the Apple App Store or Google Play Store. This process can take hours or days for review, leaving users with a broken experience in the interim.
Thesis: Decoupling JavaScript from Native Binaries
Expo solves this by separating the application into two layers: the native runtime (the binary) and the JavaScript bundle (the logic). Over-The-Air (OTA) updates allow developers to replace the JavaScript bundle on the user's device without changing the native binary, bypassing the store review process for non-native changes.
How the OTA mechanism functions
The OTA flow relies on a manifest—a JSON file that tells the app which version of the JavaScript bundle it should be running.
- Publishing: When you run the publish command, Expo bundles your JavaScript and assets, uploads them to a CDN, and updates the project's manifest.
- Checking: Upon launch, the Expo client makes a network request to the manifest endpoint (e.g.,
https://expo.dev/--/api/v2/manifest). - Updating: If the manifest indicates a newer bundle version than what is cached locally, the client downloads the new bundle in the background or foreground.
- Execution: The app then loads the new JavaScript bundle into the existing native runtime.
Worked Example: Deploying a Hotfix
Imagine a production app where a pricing label is displaying the wrong currency symbol. You need to fix this immediately without a full store submission.
1. Apply the fix in your code:
// components/PriceLabel.js
// Change from:
// return <Text>Price: {amount} USD</Text>
// To:
return <Text>Price: {amount} EUR</Text>
2. Push the update to the cloud: Run this command from your project root. You must be authenticated via the Expo CLI.
# This uploads the JS bundle and updates the manifest
expo publish
3. Verify the delivery:
To ensure the update is live without relying on a manual app restart, you can inspect the network traffic using a proxy tool or the device's remote debugger. Look for the GET request to the manifest API. A successful update is confirmed when the bundleUrl in the JSON response matches the hash of your most recent publish.
The Native Boundary: What OTA cannot do
A common engineering mistake is attempting to push native changes via OTA. Because the OTA mechanism only replaces the JavaScript bundle, it cannot modify the underlying compiled code. You must perform a full store rebuild if you:
- Upgrade the Expo SDK version.
- Add a new native library (e.g., adding
expo-cameraor a custom native module). - Modify
app.jsonorapp.config.jssettings that affect the native build (like changing the app icon or permissions). - Change the app's version number or build number.
Trade-offs and Risks
| Risk | Impact | Mitigation |
|---|---|---|
| Version Fragmentation | Offline users run old JS; online users run new JS. | Use a version-check logic in JS to prompt users to update. |
| Store Policy Violations | Apple/Google may ban apps that fundamentally change purpose via OTA. | Keep OTA updates limited to bug fixes and iterative feature tweaks. |
| Runtime Crashes | A bad JS bundle can crash the app on launch. | Use expo rollback to revert the manifest to a previous stable bundle. |
Actionable Closing
To integrate OTA updates into your workflow safely, adopt these three practices:
- Use Release Channels: Never publish directly to production. Use a staging channel (
expo publish --release-channel staging) to verify the bundle on real devices first. - Audit Native Dependencies: Before every
expo publish, check if anypackage.jsonchanges included native code. If they did, skip OTA and trigger a new build. - Monitor Manifests: Implement a health check in your CI/CD pipeline to verify that the manifest endpoint returns a 200 OK status after a publish event.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.