Over-the-air updates: what you can fix without a store review

Mobile21 October 20268 min

Every app team eventually has the same evening. A bug reaches production — a date shown a day early, a button that does nothing on one Android version, a price label that disagrees with the checkout — and the fix takes ten minutes to write. Then the question is how long it takes to reach the phones. With a fully native app the answer is a new build, a store review and the slow drift of users updating. With a React Native app built on Expo, the answer for most bugs is minutes. The difference is worth understanding precisely, because the line between what can travel over the air and what cannot is exact, and crossing it by accident is how over-the-air updates break apps instead of fixing them.

Start with what an app is made of. A React Native app has two layers. The native layer is the compiled shell: the iOS and Android code, the native modules, the permissions declared to the operating system, the icon and the splash screen. The JavaScript layer is everything drawn on top: the screens, the flows, the business rules, the text, and the images bundled with them. The store build contains both. An over-the-air update replaces only the second.

That gives the rule in one sentence. If the change lives entirely in the JavaScript layer and its assets, it can be sent as an update. If it touches anything native — a new native library, an upgrade of the React Native or Expo SDK, a new permission, a change to the app's configuration, the icon — it needs a new build and a store review. Most day-to-day bugs fall on the first side. Most new capabilities fall on the second.

With Expo, updates are delivered by expo-updates. In the usual configuration the app checks for a new update when it launches, downloads it in the background, and applies it the next time the app starts, so the person using it is never interrupted mid-flow. That default matters when planning a fix: the update reaches a phone on the launch after the one that downloaded it, which for a frequently opened app is hours and for a rarely opened one may be days. Where a fix cannot wait, the app can check and reload sooner, but that is a decision to make in the design, not in the middle of an incident.

The single most important concept is the runtime version. Every build carries one, and every update is published for one. An update is only ever delivered to builds whose runtime version matches, which is what stops JavaScript written against a newer native layer from being loaded into an older one that lacks what it needs. Expo can derive the runtime version from the app version or from a fingerprint of the native project, so that any native change produces a new runtime automatically. Getting this right is not optional. A mismatched update is the classic way to send a perfectly good fix to a build that cannot run it, and the result is an app that opens to a blank screen.

Channels and branches organise the rest. A build is tied to a channel — production, a preview for testers, a staging build — and each channel points to a branch of updates. Fixes are published to the preview channel first, opened on real phones, and only then promoted to production. The step costs minutes and catches the update that worked in development and fails on a slower Android device.

Rollbacks should be decided before they are needed. If an update makes things worse, the previous update can be republished, or the channel can be pointed back to the code embedded in the store build. Updates can also be released to a share of users first and widened once the crash numbers stay flat, the same discipline as a staged rollout in the stores. And expo-updates protects against the worst case on its own: if a newly downloaded update crashes as the app starts, it falls back to the last version that worked, so a bad update does not lock people out of the app.

Then the rules of the stores, which are clear enough to state plainly. Apple's developer agreement allows an app to download interpreted code, such as JavaScript, as long as it does not change the primary purpose of the app or bypass review, and Google Play's policies allow the same for code running in a JavaScript environment. Over-the-air updates are a repair channel: fixing a bug, correcting a text, adjusting a layout, changing a rule the app already had. They are not a way to ship a different app, add features a reviewer would want to see, or enable something that was hidden during review. Used inside that line, they are routine and expected. Used outside it, they put the developer account at risk.

A few practical habits keep the channel trustworthy. Every update gets a message that says what it fixes, so that the history is readable during the next incident. Updates are published from the same source the store build came from, never from a developer's half-finished branch. Analytics and crash reports record the update identifier as well as the app version, because a crash in version 2.3 means little when three different updates of 2.3 are in the wild. And native dependencies are upgraded on a schedule, with a store build, rather than whenever an update fails because the JavaScript has quietly outgrown the native layer.

We run TRVL AIR this way, on the App Store and Google Play: one React Native codebase, most fixes delivered over the air, new capabilities released through the stores. A wrong date or a broken screen is fixed in hours rather than days, and the store review is kept for the changes that genuinely deserve one. That is the whole value of over-the-air updates — not avoiding review, but making sure that review is never the reason a simple bug stays on people's phones.

Common questions

Can a React Native app be updated without App Store or Google Play review?
Partly. Changes to the JavaScript layer and its bundled assets — screens, flows, text, business rules — can be delivered as over-the-air updates with Expo's expo-updates. Changes to native code, native libraries, permissions, the app's configuration, the icon or the React Native and Expo SDK versions require a new store build and review.
What is a runtime version in Expo updates?
A label shared by a store build and the updates made for it. An update is delivered only to builds with the same runtime version, which prevents JavaScript written for a newer native layer from loading in an older build that cannot run it. Expo can set it from the app version or from a fingerprint of the native project.
When does an over-the-air update reach users?
In Expo's usual configuration the app checks for an update at launch, downloads it in the background and applies it the next time it starts. A frequently opened app picks up a fix within hours; a rarely opened one may take days. Apps can be configured to check and reload sooner where a fix is urgent.
Do Apple and Google allow over-the-air updates?
Yes, within limits. Both allow apps to download interpreted code such as JavaScript, provided it does not change the app's primary purpose or bypass review. Over-the-air updates are accepted for bug fixes and small changes; shipping new features or a substantially different app that way breaks the stores' rules.

The service behind it

Mobile App Development

Native and cross-platform applications for iOS and Android, with the interface work held to the same standard as the engineering.

Initiate the blueprint

Tell us what you are building.

The stack, the timeline, the thing that is currently in the way. We reply to every briefing within two working days.

Honestly? You’re going to regret switching tabs.

Finding top-tier custom developers who actually care about your business scale is nearly impossible.

We are the best at what we do, and we’ve got the track record to prove it. Don’t waste time and money with second-best options.

You convinced me.
Let’s talk!