All articles
Mobile DevelopmentAugust 12, 2026 6 min read

Expo Dev Client vs Bare Workflow in 2026: When Managed Stops Being Enough

Expo's managed workflow got dramatically more capable in 2025, but there's still a line where dev client saves you and bare workflow becomes inevitable. Here's how we decide on real projects.

Every React Native team we've onboarded in the last twelve months has asked some version of the same question: do we really need to leave Expo? The honest answer in 2026 is "probably not, but the reasons to leave are more specific than they used to be." This piece is how we actually make that call on client projects.

The three-way choice nobody explains clearly

People still talk about Expo as if it's a binary — managed or bare. It hasn't been that for years, and in 2026 the practical choice is a spectrum with three anchor points:

  • Managed + Expo Go: You use only the Expo SDK modules. Fast to start, painful the moment you need anything custom.
  • Managed + Dev Client: You run expo prebuild implicitly through EAS, install any native module you like, and get a custom development client. This is where most serious apps live now.
  • Bare workflow: You own the ios/ and android/ folders. Expo modules still work, but you're responsible for upgrades, config, and CI.

The dev client middle ground is what changed the conversation. Since SDK 50, and even more so with the config plugin ecosystem maturing, we've shipped apps with Bluetooth stacks, custom video pipelines, and native SDKs from vendors who've never heard of React Native — all without touching the bare workflow.

What "managed" actually means in 2026

Managed doesn't mean "you can't use native code." It means you don't check in the native projects. expo prebuild regenerates them on demand from your app.json (or app.config.ts) and your installed config plugins. The distinction matters because it changes how upgrades work, how CI works, and how much of your team needs to know Xcode.

When managed + dev client is enough

In our experience, roughly 70–80% of the apps a product team wants to build fit cleanly inside managed with a dev client. The rule of thumb we use:

If every native dependency you need has a maintained Expo config plugin — or is trivially wrappable in one — stay managed.

Concretely, that covers:

  • Auth via Firebase, Auth0, Clerk, Supabase
  • Payments through RevenueCat, Stripe's RN SDK, or native IAP
  • Push via expo-notifications or a wrapped FCM/APNs setup
  • Analytics (Amplitude, PostHog, Segment)
  • Maps, camera, biometrics, secure storage, background location
  • OTA updates through EAS Update

A typical app.config.ts for this kind of app looks like:

import { ExpoConfig } from 'expo/config';

const config: ExpoConfig = {
  name: 'Ledger',
  slug: 'ledger',
  scheme: 'ledger',
  ios: { bundleIdentifier: 'com.acme.ledger', supportsTablet: false },
  android: { package: 'com.acme.ledger' },
  plugins: [
    'expo-router',
    'expo-secure-store',
    ['expo-build-properties', {
      ios: { deploymentTarget: '15.1', useFrameworks: 'static' },
      android: { minSdkVersion: 26, kotlinVersion: '1.9.24' }
    }],
    ['@sentry/react-native/expo', { organization: 'acme', project: 'ledger' }],
    'react-native-vision-camera'
  ],
  updates: { url: 'https://u.expo.dev/xxxxxxxx' },
  runtimeVersion: { policy: 'appVersion' }
};

export default config;

The important part isn't the specific plugins — it's that everything native is declared, versioned, and reproducible. When a new engineer joins, they run npx expo prebuild --clean and they're building the same binary as CI.

The signals that push us toward bare

We move projects to bare workflow when at least two of these are true. One usually isn't enough.

1. You're integrating an SDK with no plugin and non-trivial native config

Some vendor SDKs — usually in fintech, telematics, or hardware — ship with 40 lines of AppDelegate.swift changes, custom entitlements, method swizzling, and a demand that you initialize them before anything else. You can write a config plugin for this. We've done it. But if the SDK changes quarterly and the vendor doesn't document the diffs, the plugin becomes a maintenance tax.

2. You need to patch React Native itself or a core native module

patch-package works in managed workflows, but it's rough for native patches. If you're regularly fixing bugs inside react-native-reanimated, RN core, or a native module's Objective-C++, checking the projects in and using bare gives you a normal Git workflow instead of a synthetic one.

3. Your build has to satisfy an enterprise mobile management team

If security is going to hand you a list of Xcode build settings, custom signing arrangements, or a mandatory MDM wrapper, life is easier when the ios/ folder is a real folder they can inspect and audit.

4. You share native code with an existing iOS or Android app

Brownfield integrations — where React Native is one screen inside a larger native app — are effectively bare by definition. You're not generating the projects; they already exist.

The dev client migration most teams do wrong

When a team moves from Expo Go to a dev client, the failure mode is almost always the same: they install one native library, run eas build, get a working dev client, and never revisit their config. Six months later nobody remembers which modules require config, upgrades are terrifying, and the CI cache is a graveyard.

The playbook we follow:

  1. Convert app.json to app.config.ts immediately. You'll want conditional logic per environment.
  2. Every native module gets an explicit plugin entry, even if it "works without one." Autolinking is not documentation.
  3. Run npx expo prebuild --clean locally at least weekly. If it breaks, you find out on Tuesday, not the day before submission.
  4. Pin expo-build-properties deployment targets. iOS 15.1 minimum is our floor in 2026; anything lower and half the ecosystem's Swift packages won't link.
  5. Use runtimeVersion policies deliberately. appVersion is safer than sdkVersion once you're on a dev client, because you control when native code changes.

A concrete upgrade command that saves pain

# Full clean rebuild — do this before every SDK upgrade
rm -rf node_modules ios android
npm install
npx expo prebuild --clean
npx expo-doctor
eas build --profile development --platform ios --local

Running expo-doctor after prebuild catches version mismatches that used to only surface at build time. It's not perfect but it's saved us at least one "why is the archive failing" afternoon per project.

What bare actually costs you

Teams underestimate the ongoing cost of bare. It's not the initial expo prebuild that hurts — it's every SDK upgrade for the next three years.

In managed, an SDK bump is:

npx expo install expo@^52
npx expo install --fix

In bare, the same bump involves the Expo upgrade helper, a three-way merge against your customized AppDelegate and MainApplication, Gradle version bumps, Podfile edits, and often a build-settings review. On projects we've maintained through three SDK cycles, bare upgrades take roughly two to five days of senior engineering time each. Managed upgrades are typically under a day.

Multiply that across the lifespan of the app. If you don't have a clear reason to be bare, that time is better spent on product.

The comparison with Swift and Kotlin nobody asked for

The honest version: if your app is deeply hardware-integrated (real-time audio, ARKit, custom Metal shaders, low-level BLE), you're going to write a lot of native code either way. React Native in bare workflow with well-organized Swift and Kotlin modules is often faster to build than two separate native apps — but only if you have engineers comfortable in all three languages. If you don't, pick native. A team that ships mediocre RN because nobody understands the iOS half is worse off than a team that ships good SwiftUI.

For the other 80% of apps — content, commerce, dashboards, social, productivity, most B2B — managed Expo with a dev client is the fastest way to a maintainable production app in 2026. That wasn't true in 2022. It is now.

Where we'd start

If you're greenfield: start managed, add a dev client the moment you need your first non-Expo native module, and stay there. Write config plugins for anything custom, even small stuff, so the next engineer can read your intent.

If you're already bare and regretting it: audit which of the four migration signals actually apply to you today. We've moved two client projects from bare back to managed in the last year, and both teams got their weekends back. If you want a second opinion on the call, our mobile team does this kind of audit regularly — but you can also do it yourself in an afternoon with the checklist above.

#React Native#Expo#Mobile Development#EAS#Architecture

Want a team like ours?

72Technologies builds production software for the kind of teams who actually read this blog.

Start a project