Expo SDK or bare React Native? A decision, not a religion.
The Expo vs bare React Native debate from 2020 is mostly settled. Expo modules work in bare apps. Config plugins handle most native customization. EAS Build and EAS Update work regardless of workflow choice.
The real question is which workflow inside the Expo orbit you want: bare (you own the native folders), managed (Expo generates them), or somewhere in between (prebuild on demand).
For most new apps, start with managed. For most existing bare apps, install expo and expo-modules-core and stop there — you get the ecosystem without a migration.
The framing "Expo or bare?" treats them as a binary. They aren't. The current state of the React Native ecosystem is a spectrum, and the position you pick on the spectrum has more to do with how much native customization you need than with which "side" you're on.
This post is what each workflow actually means in 2026 and how to decide.
What changed since 2020
The old Expo vs bare arguments came from a real constraint: in 2020, the managed workflow couldn't run custom native code. You had three choices — Expo and accept the limits, eject to bare and lose the toolchain, or stay out of Expo entirely.
That tradeoff doesn't exist anymore. Four things changed:
- expo-modules-core lets you write custom native modules using Expo's modules API. Works in managed, prebuild, and bare workflows.
- Config plugins let you modify native projects through configuration instead of direct file edits. Most "I need to edit AndroidManifest.xml" cases now have a config plugin.
- Prebuild generates native projects from configuration on demand. You can have managed-style configuration but still drop into bare editing when needed.
- EAS Build and EAS Update work for any React Native project, not just Expo managed ones. The "Expo only" toolchain era is over.
The result: nobody is forced to pick between toolchain quality and native flexibility anymore.
The workflow spectrum
Four positions, increasing in how much native code you own.
| Workflow | Native folders in repo? | Use case |
|---|---|---|
| Managed | No (generated at build) | Most new apps, especially without heavy native customization |
| Prebuild | Generated on demand, optionally committed | Apps that need occasional native access but want the upgrade story of managed |
| Bare + Expo modules | Yes, committed | Existing bare apps that want the Expo ecosystem without a migration |
| Pure bare | Yes, committed, no Expo | Specific constraints (regulated environment, can't use EAS, strong preference) |
You can move along this spectrum. You're not locked in by your starting choice.
Managed workflow
The default Expo experience. Your repo has app.json (or app.config.js) but no ios/ or android/ folders. Native code gets generated at build time.
What you get:
- The cleanest upgrade story in the ecosystem — bump SDK version, regenerate native code, done
- EAS Build, EAS Update, EAS Submit — fully integrated
- Every Expo library works out of the box
- Config plugin ecosystem handles most native customization (permissions, entitlements, splash screens, app icons, deep links, push)
- Continuous native generation — no "the native folder drifted" surprises
Where it gets awkward:
- Native debugging is a step removed. You have to run
expo prebuildto see the generated native code, and you can't directly edit it — your edits get blown away on next prebuild. - Some legacy native libraries don't have config plugins. You'll write one yourself, or fork the library.
- Build-time customization is harder when the answer is "modify a deep native build script."
For most apps that don't have a strong native customization story, managed is the right default in 2026.
Prebuild workflow
The middle position. You use Expo's configuration system, but you run npx expo prebuild to materialize the ios/ and android/ folders into your repo. Then you can commit them, edit them directly, or regenerate them whenever you want.
What you get:
- Full native access — open Xcode, edit Info.plist, add a build phase, whatever you need
- Most of the managed workflow benefits when you don't need native access
- A clean migration path back toward managed if you decide to drop the customization
The cost:
- Once you commit the prebuild output, it can drift from the configuration. Re-running prebuild will overwrite your edits unless you preserve them through config plugins.
- You're now responsible for keeping the native folders in sync across upgrades.
The honest version: most teams that pick prebuild end up at "bare with Expo modules" within a few months, because they edit the native folders and stop running prebuild. That's fine — it's the workflow they actually want.
Bare with Expo modules
You have ios/ and android/ in your repo, edited directly. You also have expo and expo-modules-core installed. Most existing React Native apps that didn't start as Expo are here, even if they don't realize it.
What you get:
- Direct native control — same as you've always had
- Access to the Expo modules library (camera, image picker, file system, secure store, notifications, etc.)
- EAS Build and EAS Update if you want them
- No forced migration of existing code
The trade-off:
- You're maintaining your own native code. Upgrades touch
Podfile,build.gradle,AppDelegate.swift, and similar files. You handle the diff yourself. - Some Expo features (config-plugin-driven setup) require an extra step in bare projects.
For an existing bare React Native app, this is the easiest move: npx install-expo-modules and you're done. You haven't migrated; you've upgraded your toolchain.
Pure bare
The fourth position. No Expo dependencies at all. Just React Native CLI, your own build scripts, your own update infrastructure.
Reasons to be here in 2026:
- Regulatory environment that forbids the EAS hosted services and where Expo's other dependencies aren't acceptable
- Specific constraint that's incompatible with Expo's runtime (rare)
- Team preference and willingness to operate the rest of the infrastructure yourself
That's the list. The "Expo is bloated" or "Expo is slow" arguments don't hold up against current versions. If you're pure bare for technical reasons, identify them concretely — most "technical reasons" people give for staying pure bare don't survive a 20-minute audit.
How to decide
For a new project:
- Default to managed. You can move toward bare later if you discover constraints. You almost never need to.
- If you know you'll need custom native code, still start with managed. Add config plugins or write Expo modules when you actually hit the constraint.
- If you have a hard requirement that managed can't serve (an unsupported native dependency, a build-system requirement, a regulated environment), start with prebuild or bare-plus-Expo.
For an existing bare project:
- Install
expoandexpo-modules-core. This is a one-time, low-risk move that unlocks the ecosystem. - Try EAS Build for one release. It usually replaces your CI pipeline cleanly.
- Don't migrate to managed. The migration from bare to managed is non-trivial, and you don't need it. Stop at "bare with Expo modules" unless you have a specific reason to keep going.
Migrating between workflows
Common moves and what they cost.
Pure bare → Bare with Expo modules
One command: npx install-expo-modules. Adds expo and expo-modules-core to your project, modifies AppDelegate and MainApplication to register the Expo modules runtime. Usually a single-PR change with low risk. This is the move almost every bare app should make.
Bare → Prebuild
Generate app.json/app.config.js, run expo prebuild, reconcile the generated native folders with your existing ones. Heavier lift — anywhere from a day to a week depending on customization. Worthwhile when you want to clean up native config that's drifted.
Prebuild → Managed
Delete the committed ios/ and android/ folders. The configuration must already be complete in app.json/app.config.js and your config plugins. Possible only if you haven't been editing the native folders directly.
Managed → Bare (eject)
Run expo prebuild and commit the result. You now own the native folders. Reversible (just delete them again) until you start editing them. Don't do this on a whim; the moment you edit native files, going back to managed is harder.
Upgrading and reconsidering the workflow?
A major React Native upgrade is the natural moment to evaluate workflow. The dependency graph is already changing; adjusting workflow is incremental cost. Run the free scanner against your current lockfile to see which libraries are compatible with each path.
Frequently Asked Questions
What's the difference between Expo and React Native?
React Native is the framework. Expo is a toolchain and library suite built on top of React Native that provides build infrastructure (EAS Build), over-the-air updates (EAS Update), submission tooling, and a large library of pre-built native modules. You can use React Native without Expo (bare workflow) or with Expo (managed or prebuild workflow). Most current React Native apps use at least parts of Expo even if they don't adopt the full managed workflow.
Do I have to use Expo to build React Native apps?
No, but the case for staying entirely outside Expo has weakened. The bare React Native CLI still exists and works. Most of the popular tooling that makes a project easy to maintain — EAS Build, EAS Update, expo-modules — works in bare workflows now. Choosing bare means choosing to operate your own build infrastructure and to write more native glue code yourself. That's a valid choice for some teams; it's overhead for most.
What is the Expo managed workflow?
The managed workflow is the Expo configuration where you don't have ios/ and android/ folders in your repo. Native projects are generated from your app.json/app.config.js configuration on demand by the prebuild step. You write all customization through config plugins. The trade-off is: you give up direct native editing in exchange for a project that's much easier to upgrade and harder to break. Most new Expo projects use this workflow.
Can I add custom native code in Expo's managed workflow?
Yes, through two paths. Config plugins let you modify the generated native projects programmatically — adding entitlements, modifying Info.plist, injecting permissions. For full custom native modules, you write them as Expo modules (using expo-modules-core's API), which works in both managed and bare workflows. The "managed workflow can't do custom native" framing is several years out of date.
What is Expo prebuild?
Prebuild is the command (npx expo prebuild) that generates ios/ and android/ folders from your app.json/app.config.js and the config plugins of your installed libraries. You can run prebuild on demand and commit the generated folders (bare workflow with Expo modules), or treat them as build artifacts that get regenerated each time (managed workflow / continuous native generation). It's the bridge between configuration-driven and file-driven native code.
Should I migrate my bare React Native app to Expo?
Probably yes, but not necessarily to the full managed workflow. The easy win is installing expo and expo-modules-core in your bare project — that unlocks Expo libraries, EAS Build, and EAS Update without giving up your existing native folders. Moving further toward managed workflow is a bigger lift, but most teams that try it report that the upgrade story improves dramatically. Migrate incrementally; you don't have to commit to the destination upfront.