Shipping faster with Expo EAS: the setup I reach for
A pragmatic EAS build and update setup — three profiles, OTA updates on the right channels, and the guardrails that keep releases boring.
Every Expo project I start eventually grows the same EAS configuration, so I've stopped reinventing it. Here's the shape that's held up across a few apps.
Three build profiles, no more
eas.json tends to sprawl. I keep it to three profiles that map to three questions:
"is this for me", "is this for the team", or "is this for users?"
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"channel": "preview"
},
"production": {
"channel": "production",
"autoIncrement": true
}
}
}
- development — a dev client I install once and iterate against with Fast Refresh.
- preview — an internal build the team can install from a link before a release.
- production — store builds, with
autoIncrementso I never hand-bump versions.
OTA updates on matching channels
The point of EAS Update is to fix a typo without a full store round-trip. The trap is pushing an update to the wrong audience. Tie each channel to its build profile and never cross the streams:
# Ship a JS-only fix to the internal testers
eas update --channel preview --message "Fix empty-state copy"
# Promote the same commit to everyone
eas update --channel production --message "Fix empty-state copy"
Rule of thumb: native change → new build; JS/asset change → update. If you touched a native module or config plugin, an OTA update won't carry it.
Guardrails that keep releases boring
A few small habits prevent most incidents:
- Gate production updates on the runtime version. An update built against a newer
native runtime should not land on an older binary. Set
runtimeVersionto{ "policy": "appVersion" }(or fingerprint) so mismatched updates are simply not served. - Preview before promote. I never
eas update --channel productioncold — it goes topreviewfirst, gets a smoke test, then I promote the exact same commit. - Watch the rollout. After a production update, glance at install and error counts before walking away. A regression is cheap to roll back and expensive to ignore.
Wiring it into CI
Once the profiles exist, CI is thin. On a tagged commit, build production and submit;
on a push to main, publish a preview update. Keep the credentials in EAS, not in the
workflow file, and let eas build/eas submit do the heavy lifting.
None of this is clever — that's the point. The goal is releases that are so routine they're forgettable, which frees up attention for the actual product.