Expo or bare React Native: which should you start with?

Robin Faraj

Robin Faraj

9/10/2026

#React Native#Expo#Mobile Development

Most of the answers you will find to this question were written before development builds existed. They tell you that Expo is the easy option with a ceiling, and that serious apps eject to bare. That was true once. It has not been true for a while, and the advice has not caught up.

What Expo is now

Expo is not a runtime you are locked inside. It is a set of libraries, a build service, and a way of generating the native projects instead of keeping them by hand.

The part people remember is Expo Go, the app you install from the store to preview a project. Expo Go ships with a fixed set of native modules baked in. If your app needs a native module that is not in that set, Expo Go cannot run it. That single limitation is where most of the "you will outgrow Expo" advice comes from.

Development builds removed it. A development build is your own app binary, with your own native dependencies compiled in, that still connects to the Expo dev server and still reloads on save. You get the same workflow, running your actual native code. Expo Go is now the throwaway option for the first hour of a project, not the thing you are stuck with.

What bare actually means

A bare project keeps ios/ and android/ directories in your repository, and you own them. You edit the Xcode project, the Gradle files and the manifests directly.

That is real control, and it has a real recurring cost. Those directories are where React Native upgrades hurt. When a new version changes something in the native template, a managed project regenerates its native folders and picks the change up. A bare project needs you to work out what changed and merge it by hand, in files you have edited, every time.

If you have ever spent a day on a React Native upgrade, this is where the day went.

Prebuild is the part that changes the decision

Expo's prebuild generates ios/ and android/ from your app config. You do not check them in. You describe the native configuration you want, and the native projects are produced from that description.

Config plugins are how you describe changes that used to require opening Xcode. A library that needs an entitlement, a permission string, a Gradle dependency or a manifest entry ships a plugin, and the plugin writes that into the generated project. Most libraries with native code ship one. When a library does not, you can write the plugin yourself in a few dozen lines.

This is the mechanism that makes "managed" stop meaning "limited". Both options give you the same reach into the native projects. They differ in whether you generate those projects or keep maintaining them yourself.

Side by side

Expo with prebuildBare
ios/ and android/Generated, not committedYours, committed, maintained
Adding a native dependencyInstall it, add its config pluginInstall it, wire it natively yourself
React Native upgradesRegenerate, resolve configMerge native template changes by hand
Building for iOSEAS Build, no Mac requiredXcode, or your own CI
Native code you cannot express as a pluginWrite a plugin, or go bareDirect
Over-the-air updates, dev client, toolingIncludedAdd and maintain separately

How to choose

Start with Expo. React Native's own documentation now points new projects at a framework rather than the bare CLI, and Expo is the one it points at. Starting bare is the choice that needs a reason.

Reasons that are still good:

You are adding React Native to an app that already exists in Swift or Kotlin. Prebuild expects to own the native projects, and yours are already there.

Some native code has no plugin that can express it, usually something that patches build phases or ships a custom toolchain.

A hard constraint on binary size, or on what the build may include, still means stripping it down yourself.

Reasons that used to be good and are not:

A native module Expo Go does not include. Build a development build.

Something in Xcode you think needs configuring by hand. Almost all of it is a config plugin now.

Wanting to leave later. You still can: npx expo prebuild writes the native projects into your repository, and you own them from that point.

Do you have to pick one?

No, and this is the part the older advice gets most wrong. The old model was a one-way door called ejecting. The current model is that the native projects can be generated or committed, and you can change your mind.

Going from managed to bare is running prebuild and committing the result. Going back is deleting the folders and moving what you changed into a config plugin, which is more work but not a rewrite.

Pick the one that fits how you work now. Changing your mind later costs about a day.

What Expo does not give you

Expo gives you the platform layer. The rest of the app is still yours to build.

Sign in with Apple and Google still needs the provider setup, the token handling, the session refresh and every screen around it. Subscriptions still need a payment provider, a paywall, restore purchases, and a server that decides what a user has paid for rather than trusting the client. Push still needs a service, a permission primer and somewhere to store the token. None of that is a React Native problem, so no React Native framework solves it for you.

That gap is the reason starter kits exist, NativeExpress among them. It is worth knowing the gap is there before you plan around it, whichever way you answer the question above.