The production playbook for OTA updates

ProductDevelopment12 minutes read

Jacob Clausen

Jacob Clausen

Engineering

Learn how to run OTA Updates safely in production with staged rollouts, real-time monitoring, and rollback strategies to ship with confidence.

The production playbook for OTA updates

Expo’s OTA update service (EAS Update) can get an update to your users in just minutes. That’s great, but sometimes it helps to go a little slower, especially when you want to observe how an update behaves in the real world.

The strongest signals come from real users, real devices, and real traffic. EAS Update is designed to propagate quickly, while still giving you control over how updates are introduced in production, and where those signals actually appear.

The more time and surface area you have to test an update, the safer it tends to be. But production rarely gives you unlimited time, and moving slowly has real costs too. EAS Update doesn't eliminate that tradeoff. It gives you control over exposure, timing, and recovery so you can choose where to sit on the spectrum for each update.

In this post, we’ll walk through a practical way to run EAS Updates in production, from staged rollouts and monitoring to aborts and rollbacks with a focus on how these mechanisms behave in real production environments.

The Expo docs describe a handful of deployment patterns examples teams use with EAS Update - from a simple two-command flow that publishes directly to production, to flows with staging channels and versioned branches that support more structured testing before release.

The specific pattern you choose will shape how you build and validate your updates, but the operational principles in this post (gradually rolling updates out, observing real signals, and responding to what you see) apply once updates reach production, regardless of workflow.

Ship small on purpose

In a production context, shipping small often means limiting exposure.

Instead of making an update immediately available to your entire user base, you can start by rolling it out to a small percentage of users. This limits the scope of exposure and gives you a chance to observe how the update behaves in the real world before expanding it further.

A rollout limits the percentage of users who can receive an update when their app checks for updates. Everyone else continues using the previous update.

In this post, we’ll use examples based on per-update rollouts, which operate on a single published update.

For example, you can publish an update with an initial rollout percentage:

Code
eas update --rollout-percentage=10

This limits both cost and impact while giving you time to see how the update behaves with real users in production.

EAS Update also supports branch-based rollouts, which gradually switch users to a different branch (a stream of updates). If you’re curious how these rollout models differ in practice, the deployment guide includes a short explanation of what types of rollouts are available.

Once you’re ready to evaluate that behavior, the next step is understanding what signals to watch and how to interpret them.

A note on update size and bandwidth

Every update a user downloads consumes bandwidth. For example, if you publish an update once a week and a user opens your app regularly, they may download several updates over the course of a month.

EAS Update includes a generous amount of bandwidth, so for most apps this isn’t something you’ll run into in normal usage. Reducing update size mainly improves reliability and gives you more room to ship updates frequently.

With the SDK 55 release, you can opt-in to Hermes bytecode diffing (currently in beta), where updates are distributed as binary patches instead of full JavaScript bundles. Instead of downloading an entire new bytecode file, the client applies a diff to what’s already installed, reducing both download size and bandwidth usage.

Bytecode diffing increases the available bandwidth headroom significantly, allowing users to download more updates while using less data than before.

Observing a rollout in production

Once an update is live to a small percentage of users, the EAS dashboard gives you a near real-time view of how that update is behaving in production.

Update adoption and volume

One of the first things to look at is how many users are actually picking up the update.

A rollout at, for example, 10% doesn’t mean 10% of users will apply the update immediately. By default, the app checks for updates on a cold start and downloads them if one is available. The update is applied the next time the app is restarted, which means users don’t all adopt it at once.

Sometimes teams tweak fallbackToCacheTimeout by a few seconds to allow the app to wait briefly for an update to download during launch so it can be applied immediately. This can speed up adoption, but it also affects startup behavior since the splash screen may remain visible while the update downloads.

More commonly, teams observe and react to the update lifecycle through the updates JS API. Hooks like useUpdates expose the state of the updates system (for example whether the app is currently checking for updates, whether an update is available, and whether one has already been downloaded) which makes it possible to coordinate update adoption after the app has rendered.

Regardless of configuration, what you’re typically looking for during a rollout is a gradual increase in adoption over time, not necessarily an immediate spike.

If adoption is unexpectedly low, that can be a signal on its own: users may not be launching the app often enough to trigger the update, or the update may not be eligible for the builds you expect - for example, because it targets a different runtime version than what those builds support.

Crashes and fatal errors

Crash data is often the clearest signal during an early rollout. Startup crashes and fatal runtime errors tend to surface quickly, because affected users will encounter them as soon as the update runs.

The first place you’ll usually notice this is in the deployment and update views in the Expo dashboard, where you can see crash counts alongside launch data for each update.

For understanding why an update is crashing, this is typically paired with external crash monitoring, such as integrating Sentry so stack traces and session context are visible alongside deployment data. Sentry will catch most runtime crashes and exceptions, but very early startup crashes may still only show up through platform crash reporting, such as App Store Connect or Play Console reports.

EAS Update also includes built-in error recovery. If a newly applied update crashes very early in the startup (before the app successfully rendered any content) the app can mark that update as failed and fall back to a previously working update. This is a defense mechanism designed to prevent the app getting to an unusable state where it crashes on launch and never runs long enough to download a fix.

Early rollout data can be noisy. Small sample sizes can exaggerate spikes or dips, especially when only a small percentage of users have received the update.

Rather than reacting to single data points, look for trends such as for example:

  • Do crash or error rates change as more users receive the update?
  • Are crashes clustered around the time the update was published?

Use these signals to decide whether increasing exposure changes the behavior you’re seeing. If crash and error rates remain acceptable as more users pick up the update, expanding the rollout is usually reasonable. If they worsen as adoption grows, pause before increasing exposure.

Expanding a rollout safely

Once an update has been running at limited exposure, the next decision is whether to let more users receive it.

Expanding a rollout doesn’t change the update itself. You’re not publishing anything new. You’re allowing a larger set of devices to become eligible to receive the same update when they next check for updates.

For example, to increase the rollout percentage:

Code
eas update:edit

An interactive guide will walk you through selecting the update and setting the new percentage.

If the signals you’re monitoring remain acceptable as exposure grows, you can keep expanding the rollout until the update is available to your full audience.

Rolling back an update

In case things go south during a rollout, you have two ways to stop or undo the update depending on how far it has progressed.

If the rollout is still ongoing, you can revert it. If the update has already reached your full audience, you can roll it back.

Reverting the rollout

While a rollout is still in progress, you can revert it. Reverting a rollout stops it and republishes the control update, returning clients to the previous state - including users who had already received the update.

Reverting is the right action when signals indicate the update shouldn’t continue rolling out, and you want to undo its impact before it reaches your full audience.

To revert an active rollout:

Code
eas update:revert-update-rollout

Rolling back after a rollout completes

Once a rollout has finished (for example, after reaching 100%) there is no rollout left to revert. At that point, if you decide the update shouldn’t be running, you use a rollback.

A rollback publishes a new update that instructs clients to run a previous version or fall back to the embedded update.

Rollbacks are used when an update has already fully rolled out and you need to move users back to a known-good state.

To roll back to a previous update:

Code
eas update:rollback

An interactive guide will assist you in selecting the type of rollback and doing the rollback.

A note on persisted state compatibility

Reverting a rollout or rolling back to a previous update assumes that older code can still run correctly with any persisted state created by the newer update.

If an update introduces non-backwards-compatible changes (for example to local storage or database schemas) returning users to an older update may cause crashes or undesired behavior.

In situations where rolling back safely isn’t possible, publishing a new update that restores compatibility may be necessary.

Debugging update issues

The Expo docs include a thorough debugging guide that walks through common failure scenarios, such as builds not receiving updates, runtime version mismatches, updates crashing shortly after launch, or assets failing to load. It also covers practical debugging strategies like inspecting expo-updates logs, verifying runtime versions, and examining update manifests.

Most update issues come down to configuration mismatches or builds not being eligible for the update you expect, and they’re usually straightforward to diagnose once you know where to look.

Wrapping up

If you haven’t used EAS Updates in production yet, it’s worth trying them out. Shipping updates directly to users can feel like a big step at first, but with rollouts, monitoring, and recovery options in place, updates become something you can introduce with confidence.

EAS Updates give you the ability to move quickly while staying in control. You can introduce changes gradually, observe how they behave with real users, and respond when needed - all within the same workflow.

EAS Update provides an outstanding developer experience, allowing teams to focus on swiftly shipping world class user experiences and improvements.

With the right operational habits in place, updates become a natural and reliable way to continuously improve your app for the people using it every day.

OTA Updates
EAS Update
over the air updates

Get there faster with Expo Application Services

Learn more