EAS Update channels and test builds: keep testers off production
· 6 min read
EAS Update lets you send JavaScript changes to apps that are already installed. That is great for test rounds: fix a typo, publish, and testers see it on their next launch. It also means a test build can quietly load the wrong code. If a preview build reads the production channel, testers see what real users see, not the change you asked them to check. This guide explains how the pieces fit, the three mistakes that cause most confusion, and how to check a build before you share it.
Expo now calls the product "Expo Update (formerly EAS Update)". The CLI is still eas-cli, so this guide uses both names.
How channels, branches and runtime versions fit together
From Expo's "how it works" page, read on November 4, 2026 (Expo docs):
- A build carries a channel. The channel name is baked in when you build, from the build profile in
eas.json. It does not change after install. - Updates go to branches. You publish with
eas update --branch preview. A channel points at a branch, so the app on channel "preview" loads updates from whatever branch that channel points at. - The runtime version must match exactly. An update only reaches builds with the same runtime version. When your native code changes, the runtime version should change, and older builds stop getting new updates.
Expo also offers percentage rollouts per update, branch based rollouts on a channel, and eas update:revert-update-rollout to undo one (rollouts docs). For production releases this is a real strength of EAS, and AppForShare does not host updates or offer anything like it.
A profile setup that keeps testers apart
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"channel": "development"
},
"preview": {
"distribution": "internal",
"channel": "preview",
"android": { "buildType": "apk" }
},
"production": {
"channel": "production"
}
}
}
Testers get builds from the preview profile. You publish test changes with:
eas update --branch preview --message "Fix checkout total"
Production users never see that update, because their builds read the production channel. When the change is ready for everyone, publish it to the production branch, using a percentage rollout if you want to start small.
Three mistakes that mix testers and production
| Mistake | What testers see | Fix |
|---|---|---|
| Preview profile copied from production, still on the production channel | Production updates, not the change under test | Set channel: preview and build again |
| Native library added, runtime version unchanged | An update that expects native code their build does not have, often a crash on launch | Change the runtime version and ship a new build |
| Development client build sent to testers | A launcher screen or an error, because there is no dev server | Share a preview build instead |
A fourth case is not a mistake but surprises people: after a native change with a new runtime version, the old test builds keep running and simply stop receiving updates. Testers who never install the new build keep testing old code. A stable link that always opens the newest build helps here, more on that below.
Check the build before you share it
None of these problems show in the file name, and testers cannot tell you which channel their build reads. AppForShare reads it from the build itself. When you upload an Expo build, the build page shows the Expo SDK, whether updates are on, the runtime version, the update URL and the update channel, read from Expo.plist on iOS and AndroidManifest.xml on Android. This is part of the readiness check that runs on every build, on every plan with an account.
The readiness check adds lines for the cases above:
- a development client build sent to testers,
- a test build that reads the production update channel,
- a runtime version that changed (a native change, so testers need this build), or one that stayed the same while a new native library appeared.
"What changed" between two builds shows when the runtime version or channel moved. From a terminal, npx appforshare info <build id> prints the same facts (the CLI needs Pro or Team), and the MCP tool build_info gives them to an AI coding tool (MCP server).
AppForShare only reads these values. It does not host updates, has no SDK, and does not change what your app downloads.
Two kinds of channels
The word "channel" means two different things here, and it helps to keep them apart:
- EAS Update channel: which JavaScript updates an installed build downloads. Set at build time.
- AppForShare channel (Pro), such as Beta and Live: a stable link and QR code that always opens the newest whole build put into it. Putting an older build back into the channel is a rollback of the link; it does not change apps already installed (Beta and Live channels).
A simple mapping works for most teams: builds from the EAS preview profile go into the AppForShare Beta channel. With Connect Expo (Pro and Team), the build profile map does that for you: every finished preview build lands in Beta by itself (Connect Expo).
A test round that stays clean
- Native change? Build the preview profile on EAS. It lands in the Beta channel. Testers open the same Beta link and install the new build.
- JavaScript only? Run
eas update --branch preview. Testers keep the build they have and get the change through EAS Update. - Collect feedback. Testers report from the install page with screenshots, or from inside the app through the in-app feedback link, no SDK (tester feedback). Each report records the build it came from.
- Release. Build the production profile, upload with
eas submitor send an uploaded store build to TestFlight or a Play testing track from AppForShare (store upload, Pro). Then roll out updates on the production branch with EAS.
For a longer look at testing an update before it reaches users, see testing an OTA update before release. For how update services differ from installing a whole build, see OTA install vs CodePush.
More for EAS teams: how EAS internal distribution links work, sending every build from Expo Workflows and sharing your app now that Expo Go needs a login.
Common questions
Can I change a build's update channel after it is installed?
The channel is set in the build. To move testers, change which branch the channel points at, or ship a new build with another channel.
Does AppForShare send over the air updates?
No. It shares whole builds and has no SDK. Keep EAS Update for JavaScript updates.
Which plan shows the Expo facts?
Every plan with an account, as part of the readiness check. Channels and the CLI are on Pro and Team.
Where do I start?
Read Use AppForShare with Expo EAS for the setup, and eas build --local: share the .ipa and .apk if you build on your own Mac. The comparison page lists where each tool is ahead.
Know which update channel each test build reads before testers do. Create a free account and upload your next preview build to see its Expo facts and readiness check.


