Skip to content

Build1 publisher3 min readPublished

Runtime version mismatch shrinks the 5 percent Expo canary you thought you shipped

EAS Update has no phased rollout percentage of its own, so a canary slice comes out of channel assignment you write and ship, and the recommended four-stage ramp keeps a fix off most devices for days.

The Engineer · Build desk

Illustration accompanying Runtime version mismatch shrinks the 5 percent Expo canary you thought you shipped

What happened

  • A dev.to post argues that an EAS Update published to a whole production channel at once is a single point of failure. The blast radius covers the entire user base before the first crash report is read.
  • EAS Update provides no built-in phased rollout percentage of the kind a store release offers, so nothing in the service itself catches a bad bundle partway out.
  • The post describes two staging shapes: assigning users across production-canary, production-early and production channels, or verifying a staging branch and then pointing the production channel at it.
  • Runtime version mismatches make a staged rollout fail silently, because users on an older native binary never receive the update and so never appear in the canary population.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost The ramp adds shipping delay, and the users waiting on the fix absorb it. An urgent hotfix needs a written exception, or the ramp gets skipped during the first real incident.
  • constraint Because the slice is assigned by the build or by runtime logic you wrote, resizing a canary during an incident means running a code path you built in advance.
  • decision A team that already has a rollback runbook still has to decide whether to carry staging as well. Rollback only shortens how long a bad update lives; staging cuts how many users ever get it.

A canary is a measurement only if you know which users it covered. EAS Update decides that with two objects: a channel, which is what a build points at, and a branch, which is a line of published updates linked to a channel to control which update a group of users receives [4]. What travels is a JavaScript bundle and assets, delivered to apps running the expo-updates library without a store submission [2]. Publish to a channel named production-canary and you have staged the users whose binary points at production-canary [5]. A device on an older native build whose runtime version does not match is not in your denominator at all [6].

That is where the two shapes cost different things. Channel-per-stage puts slice sizing into builds or runtime logic you write and ship, because the service offers no rollout percentage to sample real traffic with [3][5]. Branch promotion keeps one production channel and repoints it at a staging branch, so the pre-production evidence comes from internal and beta builds [5].

The delay comes from dwell time. The recommended ramp holds an update on an internal channel for up to 24 hours, then 1 to 5 percent of users for 24 hours, then 25 to 50 percent for 24 to 48 hours [7][8][9]. Take the upper bound at every stage and 96 hours pass before the update reaches more than half the install base [15]. Skipping the two-day store wait is the reason OTA exists [1]. The full ramp spends about twice that before the majority have the fix [16].

The 24-hour canary is not padding. Mobile usage is diurnal, and the dev.to post writes that a lunchtime publish which looks clean at dinner "has not yet survived a morning commute on flaky cell connections" [10]. Widen fifteen minutes after publish and you have measured lunchtime. The post also asks for crash-free sessions on the specific screens the update touched, not the global crash count [8].

Its stated scope includes guardrails "that make the whole thing automatic enough that a small team actually does it every time" [12]. The rule it gives for promotion is stricter: a deliberate, checklisted step, "never an automatic push to everyone because the first five minutes looked quiet" [11]. The published text breaks off inside the stage three description, and no crash-rate threshold for advancing appears before it does [13].

The full ramp is the right tradeoff in my context for an update that touches app startup or a payment path, and too slow for a string change. Before trusting any percentage I would pull the runtime version spread across the install base, because that is what decides whether 5 percent of users means 5 percent of users [6].

What to watch

  • An EAS Update feature that sets a rollout percentage server-side would move slice sizing out of the app binary.
  • Published detail on the fourth stage and on a crash-rate threshold for advancing would show how much of the ramp can be automated.
  • Measured data on runtime version spread in real Expo installs would show how many devices an eligibility check removes from a canary.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories