TL;DR — Migrating a bare React Native app to managed Expo is mostly a build-system migration, not a code rewrite. EAS Build, EAS Submit and EAS Update replace local toolchains. Native modules become declarative via Config Plugins. The migration is days, not weeks — but only if you do it in the right order.
If you started a React Native app three years ago, it is almost certainly bare. Many teams stay bare because they assume Expo means giving up native module flexibility — that has not been true for a couple of years. Today, the question is whether you want to keep operating two build pipelines or let EAS do it for you.
When to migrate
- Your CI for iOS and Android builds is brittle or requires dedicated runners
- Store submission is manual and prone to mistakes
- You want OTA updates and currently have nothing (or CodePush)
- You have or want to support multiple variants (staging, prod, white-label)
- You hire developers who expect Expo workflows
When to stay bare
- You depend on a native module that requires deep custom build setup not yet covered by a Config Plugin
- You ship to platforms Expo does not support (Windows desktop builds, for example)
- Your security posture forbids external build services and self-hosted EAS is not viable
Prerequisites
- React Native version recent enough to align with Expo SDK (re-base if older)
- Audit native dependencies for Config Plugin availability — most popular ones already have plugins
- Audit native code patches (anything in
android/andios/beyond what RN scaffolds) — they need to become Config Plugins - Clean signing config — EAS Build wants explicit cert + provisioning profile management
- Plan an EAS Update strategy before the cutover (channels, runtime versions, rollback paths)
The migration playbook
- Install Expo modules into the bare project. Most existing screens keep working.
- Move app config from
app.json/ native files intoapp.config.js. Capture splash, icons, bundle identifiers, deep links, capabilities. - Convert native patches to Config Plugins. Each
ios/orandroid/patch becomes a small plugin that EAS Build applies during prebuild. - Run
npx expo prebuild --cleanto regenerate the native projects. Diff the output against the existing native folders; anything missing is a plugin you have not written yet. - Wire up EAS Build profiles (
eas.json) — typically development, preview, production. - Run a real EAS Build end-to-end for both platforms. Fix the first failures before scaling.
- Switch CI to call EAS Build instead of local Xcode / Gradle. Delete the legacy CI configuration only after a full release cycle has shipped through EAS.
- Adopt EAS Submit for store uploads, then EAS Update for OTA. Each in its own week.
The pitfalls
- Hidden manual edits in
ios/Info.plistorandroid/AndroidManifest.xmlthat nobody documented — diff the prebuild output mercilessly - Custom font installation that worked through native projects breaks after prebuild — use
expo-fontinstead - Linking edge cases — universal links and deep links need their schemas declared in
app.config.js, not justInfo.plist - EAS Update runtime versioning — get this wrong and updates ship to wrong native builds. Use
fingerprintfrom day one. - Signing — bring your existing signing assets into EAS or let EAS generate; do not run hybrid mode for long
What you get back
- No more local Xcode build problems on engineer-of-the-day’s laptop
- Faster CI, often 2–4× shorter pipelines
- OTA updates that actually work, with channels and rollback
- One build chain instead of two
- A team that can move between mobile projects without re-learning each app’s bespoke setup
Frequently asked questions
Why migrate to Expo if bare RN already works?
For most product teams the win is operational: EAS Build replaces local Xcode/Android Studio build chains, EAS Submit replaces manual store uploads, EAS Update replaces a self-hosted CodePush. The engineering bench you free up usually pays for itself.
Can I keep my custom native modules?
Yes — Expo Config Plugins let you wrap native module configuration so EAS Build applies it at build time. Modules that were patched manually in android/ or ios/ become declarative.
Working on something similar?
T-Square architects, builds and operates production systems for learning, AI and custom software products. Talk to a senior engineer if you want a second opinion on your design or roadmap.