Mobile App Development

Expo vs Bare React Native: Which Should You Pick?

Compare Expo vs bare React Native using the EAS-era prebuild model. Learn which workflow fits your team's native requirements, CI/CD setup, and long-term maintenance needs.

By Laxaar Engineering Team Jul 8, 2026 10 min read
Expo vs Bare React Native: Which Should You Pick?

Most teams picking Expo vs bare React Native treat the decision like a one-way door. They start managed, hit a native module wall, and then "eject" (a word that implies irreversibility) which usually triggers weeks of painful Xcode and Gradle debugging. That framing is out of date.

Since Expo introduced EAS (Expo Application Services) and the prebuild command, the line between Expo and bare React Native has blurred considerably. You can now run a fully managed Expo project, generate native code on demand, and still ship to the App Store and Play Store through the same CI pipeline. The two workflows aren't opposites; they're points on a spectrum.

The real question isn't "Expo or bare?" It's "how much native control do we need today, and how quickly can we acquire more?" This post answers that using the EAS-era model as the frame, not the pre-2021 eject narrative that still dominates most comparisons.

What you'll learn

What the Expo managed and bare workflows actually mean in 2026

Expo managed workflow is a configuration-first approach where your native iOS and Android projects are generated automatically by Expo at build time. You don't commit ios/ or android/ directories. Your app.json or app.config.js file is the source of truth, and Expo's SDK handles the rest.

Bare workflow is the React Native CLI-style setup where ios/ and android/ directories exist in your repo, you modify them directly, and you own every line of native code. It's the traditional model developers have used since React Native's early days.

What changed with EAS is that Expo introduced expo prebuild, which generates the native directories from your Expo config at any time. This means managed and bare are no longer different products. They're different modes of the same build pipeline. You can stay managed, generate native code when you need to inspect or modify it, and still re-generate it cleanly on the next run.

This continuous-native-generation model is the key insight. Ejecting used to mean "you're done with Expo." Prebuild means something different: you can always inspect the native output, and your config remains the canonical source.

How EAS prebuild changed the comparison entirely

expo prebuild is a command that materializes your native projects from config plugins and your app.config.js. Run it and you get an ios/ folder and an android/ folder that are reproducible. Delete them, change your config, run it again, and you get fresh native projects.

# Generate native projects from your Expo config
npx expo prebuild

# Run on a specific platform
npx expo prebuild --platform ios

The implication is significant: the "managed" vs "bare" distinction now maps to whether you keep generated native directories in version control and modify them manually. Bare workflow teams keep and commit them. Managed teams let Expo regenerate them.

Config plugins are the mechanism that makes this work for native dependencies. A config plugin is a function that modifies the generated native project during prebuild. Popular libraries like react-native-camera or any Firebase SDK ship a config plugin so they wire themselves into your native project automatically.

// app.config.js
export default {
  name: 'MyApp',
  plugins: [
    ['expo-camera', { cameraPermission: 'Allow access to camera.' }],
    ['@react-native-firebase/app', { /* firebase config */ }],
  ],
};

If a library doesn't have a config plugin, you can write one yourself or drop down to bare workflow for that project. That's the real trade-off, not Expo vs React Native as philosophies.

Native module access: where the real difference lives

The gap that matters is not about JavaScript APIs. It's about native modules that require manual AndroidManifest.xml edits, custom Gradle build flavors, custom Podfile targets, or app extensions like Widgets and Notification Service Extensions.

Bare workflow gives you full, unconditional access. You edit native files directly. Managed workflow gates that access behind config plugins, and if a plugin doesn't exist for your dependency, you're either writing one or moving to bare for that repo.

Here are the cases where bare workflow is genuinely necessary today:

  • iOS App Extensions. Share extensions, widgets, Notification Service Extensions. These require separate Xcode targets and entitlements Expo doesn't yet generate automatically for all cases.
  • Custom Gradle build variants. If you need separate APKs for paid vs free tiers with distinct signing keys and feature flags.
  • Brown-field integration. Embedding React Native into an existing native app where you control the host application shell entirely.
  • Highly customized Xcode schemes. Some enterprise distribution setups require Xcode scheme configurations that don't map cleanly to config plugin outputs.

For most consumer and B2B apps, the Expo SDK plus config plugins covers everything you'll need. The cases above are genuinely uncommon.

Build infrastructure and CI/CD trade-offs

EAS Build is Expo's hosted build service. It runs your native builds on managed macOS and Linux workers, so your developers never need Xcode locally to produce a production iOS binary. That's a genuine operational win for teams that don't want to manage build machines.

Bare workflow doesn't preclude EAS Build, and you can still use it. But the advantage narrows: if you're already maintaining a custom Podfile and Gradle configuration, you're also likely comfortable running builds on your own CI (GitHub Actions, Bitrise, CircleCI). The managed workflow gets more value from EAS Build because the build environment and the config model are co-designed.

One honest trade-off: EAS Build costs money at scale. The free tier covers moderate usage, but high-volume shipping teams can hit the paid tier quickly. With bare workflow and self-hosted macOS CI, the unit economics can flip — especially if your team already has macOS runners.

# eas.json — configure EAS Build profiles
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "production": {
      "distribution": "store"
    }
  }
}

EAS Update (formerly OTA updates via Expo Updates) works equally well in both workflows. That's one lock-in concern that doesn't actually exist: you don't have to be fully managed to use over-the-air updates.

Team skills, onboarding, and long-term maintenance

This is the dimension that comparisons usually skip. Managed Expo workflow dramatically lowers the bar for JavaScript developers contributing to a mobile project. They don't need to know CocoaPods, they don't need Xcode installed for most tasks, and environment setup is an npm install plus npx expo start.

Bare workflow requires at minimum one team member with reliable iOS and Android native experience. Not because you're writing Kotlin or Swift constantly, but because when something breaks in the native layer (a dependency version conflict in Podfile.lock, a Gradle sync failure, a code signing issue), you need someone who can diagnose it without panic.

At Laxaar, our mobile teams default to managed Expo for new projects unless there's a concrete, documented native requirement that can't be satisfied by an existing config plugin. The onboarding speed difference for new engineers is real, and forcing a bare setup prematurely adds weeks of native tooling maintenance that most product teams don't budget for.

Comparison table: managed vs bare at a glance

DimensionExpo ManagedBare React Native
Native directories in repoNo (generated at build)Yes (committed, edited directly)
Config source of truthapp.config.js + pluginsNative files directly
Xcode required locallyNo (EAS Build handles it)Yes, for most native work
Native module supportVia config pluginsUnrestricted direct access
App Extensions (Widgets, etc.)Limited / manualFull support
OTA updates (EAS Update)SupportedSupported
Brown-field embeddingNot supportedSupported
Onboarding time for JS devsLowMedium-high
Build cost at scaleEAS Build pricingSelf-hosted CI possible
Upgrade pathManaged SDK upgradesManual React Native upgrades

When to choose Expo managed, when to go bare

Choose Expo managed when:

  • The team is JavaScript-first with limited native iOS/Android experience.
  • You need fast onboarding and don't want Xcode to be a dependency.
  • All required native modules have Expo SDK equivalents or config plugins.
  • You want EAS Build, EAS Submit, and EAS Update as a unified CI/CD pipeline.
  • The app is greenfield and product requirements are still evolving.

Choose bare React Native (or Expo with bare workflow) when:

  • You're integrating React Native into an existing native app.
  • You need iOS App Extensions or custom Xcode targets.
  • You have custom Gradle build variants or flavor dimensions.
  • A critical native dependency has no config plugin and you can't wait for one.
  • You're already running native-capable CI (macOS runners with Xcode) and the EAS Build cost model doesn't make sense.

There's a third option worth naming: Expo bare workflow with prebuild. You use Expo's SDK and config plugin ecosystem but commit your native directories. Native access stays unrestricted. Expo tooling stays intact. At Laxaar, projects often land here organically: they start managed, add a native requirement or two, commit the ios/ and android/ folders, modify them carefully, and re-generate only when the team wants a clean native reset.

If you're building a mobile application and unsure where on this spectrum to start, the Laxaar team's honest recommendation is: start managed, write down every native capability you think you'll need in year one, and check each against the Expo SDK and the community config plugin registry before concluding you need bare. Most lists shrink considerably on that exercise.

For teams building more complex native-heavy apps, our custom software development practice can help scope the architecture decision before you commit to a codebase structure.

Frequently Asked Questions

Is "ejecting" from Expo still a thing in 2026?

The expo eject command was deprecated and replaced by expo prebuild. Ejecting implied a permanent, irreversible migration away from Expo's tooling. Prebuild generates native code reproducibly from your config, so you can return to a clean native baseline at any time. Most documentation and tutorials still use the old "eject" framing. Skip it and read the current Expo docs instead.

Can we use react-native-camera or Stripe SDKs in managed Expo?

Yes, in most cases. Popular libraries like react-native-vision-camera, @stripe/stripe-react-native, and Firebase SDKs all ship config plugins compatible with managed Expo. Before assuming a library requires bare workflow, check whether a config plugin exists in the library's README or in the Expo community plugins registry. The gap has narrowed significantly since 2022.

Does bare React Native mean we can't use Expo SDK modules?

No. Expo SDK modules, including expo-camera, expo-notifications, expo-location, and others, can be used in bare React Native projects. The SDK is not exclusive to managed workflow. You lose Expo Go compatibility (the quick-start development client), but you can create a custom development client with expo-dev-client that supports your additional native modules.

How does the Expo SDK upgrade process compare to React Native upgrades?

Expo SDK releases are quarterly and bundle a tested set of React Native and native library versions. Upgrading Expo SDK is typically one version bump in package.json plus a prebuild re-run. Bare React Native upgrades require manually applying React Native's upgrade diffs using the React Native Upgrade Helper, which touches native files directly and is more error-prone. The managed upgrade story is a genuine advantage for teams that don't want to own upgrade coordination.

When does EAS Build cost become a concern?

EAS Build's free tier (as of mid-2026) includes a limited number of build credits per month. For solo developers and small teams shipping infrequently, it's more than adequate. For teams shipping multiple times per week across iOS and Android, particularly with separate development and production build profiles, costs can climb. At that volume, compare EAS Build pricing against the operational cost of maintaining macOS CI runners (either self-hosted or GitHub's macOS runners), factoring in the engineering time saved on native tooling.

If you're evaluating mobile development approaches for a new product or need a second opinion on a current architecture decision, the Laxaar mobile team is happy to walk through your requirements. We've run Expo managed, bare, and hybrid setups across dozens of projects and can give you a direct read on which fits your specific stack and team. See our mobile and product work for reference.

Working on something like this?

Get a fixed scope, timeline, and price within one business day — no obligation.

React NativeExpoMobile Development
Grow your business with us

Take your business to the next level.

Tell us what you're building. We'll come back inside one business day with a fixed scope, timeline, and team — or an honest “this isn't a fit”.

ENGINEERING PHILOSOPHY

Code is useless if it's not comprehensible to those who maintain it. We write code the next person can actually understand.