React Native2024-08-10|6 min read

Expo vs Bare Workflow in React Native: Which Should You Choose in 2024?

The Expo vs bare workflow debate has been a constant in React Native teams since Expo launched. In 2024 the landscape looks meaningfully different from three years ago — EAS Build, Expo Modules API, and Config Plugins have blurred the line considerably. If you're starting a new project or evaluating a migration, here's how I think about the decision after shipping apps in both setups.

Managed vs Bare at a Glance

In the managed workflow, Expo owns the native layer. You write JavaScript and Expo's SDK handles camera, notifications, file system, and everything else. You never open Xcode or Android Studio unless something goes wrong. In the bare workflow, you have the full native project — ios/ and android/ directories checked into git — and you're responsible for native dependencies, signing, and build configuration.

A middle path exists: the bare workflow with Expo modules. You keep the native directories but use Expo's curated SDK and Config Plugins to manage most native configuration automatically. This is what most production teams end up on.

When to Use Managed Workflow

  • You're prototyping or building an MVP and want to move fast.
  • Your feature set is covered by the Expo SDK (camera, maps, push notifications, local storage, sensors).
  • Your team has limited native iOS/Android experience.
  • You want to use Expo Go for instant team previews without a build step.

Managed workflow is genuinely excellent for these scenarios. I've shipped two internal tools using it and the developer experience — especially with Expo Router for file-based navigation — is hard to beat.

When to Go Bare

  • You need a native module with no Expo SDK equivalent and no Config Plugin.
  • You're integrating a proprietary SDK delivered as a binary (e.g., a payment terminal, Bluetooth device, or enterprise SSO library).
  • You need fine-grained control over build.gradle or the Podfile — app variants, custom build phases, CocoaPods subspecs.
  • Your app has strict binary size requirements — the Expo managed runtime adds overhead.

EAS Build Changes the Equation

Historically, the managed workflow's biggest limitation was that you couldn't build a standalone binary locally without ejecting. EAS Build removed that constraint. You can now build a managed app as a production IPA or APK in CI without any Mac runners — Expo's cloud infrastructure handles it.

# Install EAS CLI
npm install -g eas-cli

# Configure your project
eas build:configure

# Build for both platforms
eas build --platform all --profile production

EAS Build supports both managed and bare workflows, so switching between them is less disruptive than it used to be.

Config Plugins: Native Power Without Ejecting

Config Plugins let you modify native files declaratively from app.config.js. Many popular libraries now ship their own plugin:

// app.config.js
export default {
  expo: {
    plugins: [
      ["expo-camera", {
        "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera."
      }],
      ["@react-native-firebase/app", {
        "googleServicesFile": "./google-services.json"
      }],
      ["expo-build-properties", {
        "android": { "compileSdkVersion": 34 },
        "ios": { "deploymentTarget": "15.0" }
      }]
    ]
  }
};

A Config Plugin runs at build time and patches the native project automatically. If a plugin exists for your dependency, you get native integration without ever opening Xcode.

Migrating from Managed to Bare

If you hit a wall in managed workflow, migration is straightforward:

npx expo prebuild

This generates the ios/ and android/ directories from your current config. From this point you're in the bare workflow. The generated files become yours to own — commit them and treat them like any other native project. You keep all Expo SDK packages and EAS services.

My Recommendation

Start with managed workflow and expo prebuild only when you genuinely need it. In 2024, Config Plugins cover the vast majority of native integration needs without ejecting. If you're building a healthcare app, an enterprise tool with a proprietary SDK, or an app with multiple build variants, start bare from day one — the complexity is lower when you design for it upfront rather than migrating mid-project.