Expo vs Bare React Native: Workflow Comparison
AI generated
</>
{ }
React Native · Expo · Toolchain · Mobile Development
Expo vs Bare React Native
the workflow comparison for 2026

Expo has grown from a limited sandbox into a full toolchain for React Native that now supports even complex native modules. The bare workflow still matters when maximum native control is required. This article shows how Expo really works today and when switching to bare is actually necessary.

17 min read Expo · EAS Build · Prebuild · Development Build React Native 0.76+ · Expo SDK 52+

1. Why the Expo versus bare question sounds different today

A few years ago, the decision between Expo and the bare workflow was still simple: Expo was convenient but limited, while bare React Native offered full control at the cost of more setup effort. Switching from Expo to bare used to mean an irreversible eject step, after which the generated iOS and Android folders had to be maintained manually. Those days are over. With prebuild, config plugins and development builds, Expo has grown into a toolchain that supports nearly any native module without giving up the conveniences of the managed workflow.

Still, choosing between Expo and bare React Native remains a strategic decision with consequences for build time, CI pipeline and team onboarding. Anyone who does not cleanly distinguish the two models often makes the choice based on outdated assumptions, for instance believing Expo is only suitable for prototypes. In practice, large production apps with millions of users run on pure Expo, while other teams deliberately choose bare because they need deep access to native build configuration.

This article maps out both workflows along their actual technical differences: where Expo removes work, where prebuild acts as a bridge, and when the pure bare workflow really is the better choice.

2. The Expo managed workflow in detail

The Expo managed workflow bundles the entire native toolchain behind a declarative configuration file, app.json or app.config.js. Instead of manually maintaining Xcode projects and Gradle files, you define app name, bundle identifier, icons, splash screens and permissions centrally in this one file. During the build, Expo automatically generates the native project structures from it, without a developer ever having to open a native project in an editor.

This model significantly lowers the entry barrier for web developers, since no Xcode knowledge and no Gradle knowledge are needed to build a working app. At the same time, Expo ships an extensive set of preconfigured modules, from camera to location to secure storage, all already tested and equipped with correct permission requests. For teams without dedicated mobile experience, this head start is often decisive for time to market.


{
  "expo": {
    "name": "ShopApp",
    "slug": "shop-app",
    "version": "2.4.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#0f172a"
    },
    "ios": {
      "bundleIdentifier": "de.mironsoft.shopapp",
      "supportsTablet": true
    },
    "android": {
      "package": "de.mironsoft.shopapp",
      "permissions": ["CAMERA", "ACCESS_FINE_LOCATION"]
    },
    "plugins": [
      "expo-camera",
      "expo-location",
      ["expo-build-properties", { "ios": { "deploymentTarget": "15.1" } }]
    ]
  }
}

3. EAS Build and EAS Update: Expo's cloud infrastructure

EAS, short for Expo Application Services, is the cloud infrastructure that turns Expo from a pure development library into a full build and release platform. EAS Build compiles native iOS and Android binaries in the cloud, without a local Mac being required for iOS builds. That is a significant advantage over the classic bare workflow, where iOS builds must run on macOS hardware, either locally or through a self hosted CI infrastructure.

EAS Update complements EAS Build with over the air updates for JavaScript and asset changes, without going through a new app store review cycle. Important in practice: EAS Update only works for code changes, not for native changes such as a new native module or a modified Info.plist. Anyone who does not know this distinction may accidentally publish an update that does not take effect on older, already installed binaries, because the underlying native runtime is not compatible.


# Build a production iOS binary in the cloud, no local Mac needed
eas build --platform ios --profile production

# Build both platforms for internal testing
eas build --platform all --profile preview

# Push a JS-only update to production channel without app store review
eas update --branch production --message "Fix checkout validation bug"

4. Development builds instead of Expo Go

Expo Go, the generic app from the app stores, used to be the only way to test an Expo app on a real device. The decisive drawback: Expo Go only contains a fixed selection of preinstalled native modules and cannot load additional native libraries that are not already part of the Expo Go runtime. This limitation was for years the main reason teams switched to bare React Native early, as soon as they needed to integrate a library outside the Expo ecosystem.

Development builds solve this problem entirely. Instead of the generic Expo Go app, you build your own project specific development app that contains exactly the native modules the project actually needs, including third party libraries outside the Expo ecosystem. This approach combines the development speed of Expo, for instance hot reloading and fast refresh, with the full native flexibility that used to be exclusive to bare React Native.

5. Prebuild: the bridge between Expo and bare

expo prebuild is the command that translates the declarative app.json configuration into actual ios/ and android/ directories, exactly as a pure bare React Native project would have. The decisive difference from the historical eject command: prebuild is repeatable. You can delete ios/ and android/ at any time and regenerate them with expo prebuild --clean, without losing manual changes to these folders, as long as those changes were made through config plugins rather than directly in the generated code.

This model lets many teams stay permanently in declarative mode and never check the native folders into version control at all. Other teams deliberately decide to permanently commit the native folders after the first prebuild and maintain them manually going forward, which effectively matches the classic bare workflow, just with Expo modules as the starting point. This flexibility makes Expo compatible today with almost any project maturity, from the first prototype to a complex enterprise app.

6. The bare workflow: full control, full effort

The bare React Native workflow means working directly with the generated ios/ and android/ projects, without the abstraction layer of Expo prebuild. Xcode project settings, Gradle build scripts and native manifest files are maintained manually. This approach is mandatory when a project needs native build steps that cannot be expressed through config plugins, for instance very specific Xcode build phases, custom Gradle tasks, or integration with existing native iOS and Android codebases into which React Native is embedded as a library, rather than the other way around.

The price for this control is maintenance effort: every React Native upgrade requires manually applying changes to the native project files, a process that can take several hours to days for larger version jumps. CI pipelines have to be set up independently, including signing, provisioning profiles and app store uploads, tasks that EAS Build largely automates within the Expo ecosystem. Teams with dedicated mobile engineering expertise usually handle this effort well, smaller teams regularly underestimate it.

7. Config plugins: native customization without ejecting

Config plugins are the mechanism through which Expo enables native project customizations declaratively, without editing the generated code directly. A config plugin is a function that runs during expo prebuild and programmatically modifies the generated Info.plist, AndroidManifest.xml or Gradle build files. Many popular native libraries ship their own config plugin, so from the developer's perspective installation consists only of npx expo install and an entry in app.json.

For edge cases without a ready made plugin, custom config plugins can be written with the @expo/config-plugins package. This is considerably less effort than one might expect, since the API provides targeted, typed helper functions for the most common modifications, such as adding a permission or a framework. This mechanism is the actual reason the boundary between Expo and bare React Native is so much more permeable today than it was just a few years ago.


// A minimal custom Expo config plugin
const { withInfoPlist } = require('@expo/config-plugins');

// Adds a custom Info.plist entry during prebuild, no manual Xcode editing needed
function withCameraUsageDescription(config, usageText) {
  return withInfoPlist(config, (config) => {
    config.modResults.NSCameraUsageDescription = usageText;
    return config;
  });
}

module.exports = withCameraUsageDescription;

8. Decision criteria for practice

The decision between Expo and the bare workflow should be based on concrete project characteristics, not on blanket assumptions. Anyone with a team that lacks dedicated mobile specialists benefits significantly from EAS Build, development builds and Expo's large module ecosystem, since native toolchain complexity mostly disappears. Projects with tight timelines and a need for frequent over the air updates without app store review also benefit strongly from EAS Update.

Bare React Native is favored by concrete requirements such as integration into existing native apps, very specific build pipeline requirements that cannot be expressed through config plugins, or corporate policies that mandate fully on premise CI without external cloud services. In practice, new projects almost always benefit from starting with Expo and development builds, since switching to bare through prebuild remains possible at any time, while the reverse path from bare to Expo is significantly more effort.

9. Expo and bare React Native compared directly

The following table contrasts the central decision criteria between Expo and bare React Native and shows which workflow causes less operational overhead in which scenario.

Criterion Expo Managed Bare React Native Recommendation
iOS builds without a Mac Yes, via EAS Build No, macOS mandatory Expo when Mac infrastructure is missing
Over the air updates EAS Update built in Manual integration needed Expo for frequent hotfixes
Arbitrary native modules Via config plugins Directly, no detour Bare for very exotic modules
Integration into existing native app Limited support Fully supported Bare for brownfield projects
Entry barrier for web teams Low High, Xcode/Gradle knowledge needed Expo for new mobile teams

The table shows there is no universally correct answer, only concrete criteria that must be weighed differently depending on the project. The practical advice is usually to start with Expo and only switch to bare once a concrete requirement forces it, not out of a preemptive need for control.

Mironsoft

React Native toolchain consulting and app store rollout

Unsure between Expo and bare React Native?

We analyze your project, your existing native requirements and your team setup, and give a clear recommendation for the right workflow, including CI pipeline setup with EAS Build or classic Fastlane.

Workflow audit

Inventory of your native dependencies and requirements

EAS setup

Configuring the build and update pipeline for Expo projects

Migration

Switching between Expo and the bare workflow without data loss

10. Summary

The decision between Expo and bare React Native is far less binary today than it was a few years ago. Development builds, prebuild and config plugins have made the boundary permeable: an Expo project can integrate almost any native module without leaving the declarative configuration, and can be converted into a bare project through prebuild whenever needed. EAS Build and EAS Update additionally solve two of the biggest operational pain points of bare React Native: Mac dependency for iOS builds and slow update cycles through the app store.

For most new projects, starting with Expo is the more pragmatic choice, since switching to bare later remains possible, while the reverse path means more migration effort. Bare React Native remains the right choice for brownfield integrations into existing native apps and for teams with very specific build requirements that config plugins cannot express.

Expo vs Bare React Native, the key points at a glance

EAS Build

Cloud builds for iOS and Android without local Mac hardware, Expo's biggest practical advantage.

Development builds

Replace Expo Go and allow any native module while keeping full development comfort.

Prebuild

A repeatable bridge to native project folders, no irreversible eject required anymore.

Bare workflow

Right choice for brownfield integration or very specific build requirements without config plugin coverage.

11. FAQ: Expo vs Bare React Native

1Is Expo only for prototypes?
No, outdated assumption. Development builds and EAS Build make Expo production ready for any requirement.
2Do I still need Expo Go?
Only for very simple projects. Third party modules require a development build.
3What does expo prebuild do?
Translates app.json into real ios and android folders, repeatable with --clean.
4Can I switch to bare?
Yes, via prebuild, then permanently commit and maintain the native folders manually.
5Do I need a Mac?
Not with EAS Build, which compiles iOS in the cloud. The bare workflow requires macOS.
6Does EAS Update always work?
Only for JS and asset changes, native changes need a new build and review.
7What is a config plugin?
A function that programmatically adjusts native files during prebuild, no manual editing needed.
8When is bare mandatory?
For brownfield integration into existing native apps or very specific build requirements.
9Do I lose performance with Expo?
No, development builds compile to the same native binary as bare React Native.
10How should I start?
With create-expo-app and directly a development build. Switching to bare stays possible later.