◉RORK LABJP
●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●SDK 58 — SDK 58 Beta has been out since Sep 15. The stable date is still unconfirmed●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 3 days left●Q&A — People are asking why expo-widgets render blank only in production builds●RORK — GPT-6.1 Sol was added on Sep 29, available on Pro and Max plans●NEW — Building an app for a client? Decide who owns the publishing account first●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●SDK 58 — SDK 58 Beta has been out since Sep 15. The stable date is still unconfirmed●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 3 days left●Q&A — People are asking why expo-widgets render blank only in production builds●RORK — GPT-6.1 Sol was added on Sep 29, available on Pro and Max plans●NEW — Building an app for a client? Decide who owns the publishing account first
Articles/Dev Tools
⬡ Dev Tools/2026-06-28Advanced

Ship EAS Updates to a Few First, and Halt Automatically on Crash Rate

Because OTA updates reach everyone instantly, a bad update reaches everyone instantly too. Here is a three-layer design: ship EAS Update to a small canary, decide expand-or-halt from crash-free rate automatically, and hold a safety net on the device — with working code.

Rork577Expo213EAS Update7OTA7indie developer41

✦ Premium Article

OTA updates — swapping the JavaScript bundle — have a big upside: you can deliver a fix without waiting for store review. But the same property is also the scary part. If a good update reaches everyone instantly, so does a bad one.

As an indie developer at Dolice, I once pushed a small fix over the air and dragged in a bug that crashed on launch for one specific device configuration. For the tens of minutes until I noticed and reverted, everyone who received the update could not open the app. The cause was a single line of code, but the real problem was the delivery method: it reached everyone at once.

This article lays out a three-layer design: ship EAS Update to a few first, let crash-free rate decide expand-or-halt automatically, and hold a safety net on the device too.

Why "ship to everyone at once" is dangerous

With store delivery, review and phased release act as buffers even if a bad build ships. OTA removes those buffers to gain speed, so you have to provide the buffers yourself.

DeliveryReach of a bad updateGrace before you notice
Instant to everyoneAll usersAlmost zero
Canary 5%5% of usersYou can decide before expanding
Canary + auto-rollbackOnly part of the 5%Minutes until the machine halts it

The goal is the bottom row: a state that does not rely on human watching, halts delivery on a bad signal, and lets the device defend itself.

Layer one: canary delivery via rollout percentage

EAS Update has a rollout feature that controls what percentage of devices receive a single update. Publish to a small fraction first, not everyone.

# ship to 5% first
eas update --branch production \
  --message "fix: crash on cold start" \
  --rollout-percentage 5
 
# expand in steps if all is well
eas update:edit --branch production --rollout-percentage 25
eas update:edit --branch production --rollout-percentage 100

Bumping the percentage by hand is fine, but visually gathering the deciding signal (crash-free rate) every time is impractical. We automate that in the next layer.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Concrete commands and operations for canary delivery via EAS Update rollout percentage
✦A script that mechanically decides expand/hold/rollback from crash-free rate
✦A device-side safety net using expo-updates to catch crash loops and fall back to the embedded bundle
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-08-09
Measuring Hermes Bytecode Delta Updates: One Added Module Cost 29x More Than One Changed Line
I measured OTA delta sizes against a 2.4MB Hermes bytecode bundle. Changing one line cost 2,104 bytes; adding one module cost 61,197. The widely repeated advice about stable module IDs turned out to matter least.
⬡ Dev Tools2026-05-23
Auditing Privacy Manifests for Rork-Generated Expo Apps — A One-Day Pre-Submission Workflow for Indie Developers
A pre-submission workflow for indie developers shipping Rork-generated Expo apps: enumerate every dependency, tell ITMS-91053 apart from ITMS-91061, and catch the Pods that npm names never show you — hermes included.
⬡ Dev Tools2026-03-14
Moving Six Apps to EAS CI/CD — EAS Build, OTA Updates, and GitHub Actions in Practice
How I moved the build and release pipeline for six indie apps to Expo Application Services: EAS Build for iOS and Android, OTA updates with EAS Update, GitHub Actions integration, and honest notes on free-tier limits.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links