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.

Bare RN → managed Expo migration stepsMostly build-system migration. Native patches become Config Plugins applied by EAS Build at prebuild time. — /migration steps Bare RN android/ + ios/ folders Managed Expo app.config.js + EAS 1Install expo modules 2Move config → app.config.js 3Patches → Config Plugins 4expo prebuild –clean 5eas.json profiles 6First EAS Build (both) 7CI → EAS Build 8EAS Submit + Update
Mostly build-system migration. Native patches become Config Plugins applied by EAS Build at prebuild time.

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/ and ios/ 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

  1. Install Expo modules into the bare project. Most existing screens keep working.
  2. Move app config from app.json / native files into app.config.js. Capture splash, icons, bundle identifiers, deep links, capabilities.
  3. Convert native patches to Config Plugins. Each ios/ or android/ patch becomes a small plugin that EAS Build applies during prebuild.
  4. Run npx expo prebuild --clean to regenerate the native projects. Diff the output against the existing native folders; anything missing is a plugin you have not written yet.
  5. Wire up EAS Build profiles (eas.json) — typically development, preview, production.
  6. Run a real EAS Build end-to-end for both platforms. Fix the first failures before scaling.
  7. 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.
  8. Adopt EAS Submit for store uploads, then EAS Update for OTA. Each in its own week.

The pitfalls

  • Hidden manual edits in ios/Info.plist or android/AndroidManifest.xml that nobody documented — diff the prebuild output mercilessly
  • Custom font installation that worked through native projects breaks after prebuild — use expo-font instead
  • Linking edge cases — universal links and deep links need their schemas declared in app.config.js, not just Info.plist
  • EAS Update runtime versioning — get this wrong and updates ship to wrong native builds. Use fingerprint from 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.