"We're going to start in Expo, but sooner or later we're going to eject."
"Does Expo support my use case or will I need to eject?"
"I haven't ejected yet, but..."

You won't make it through many React Native threads before coming across statements like these.

Ejecting is another word for opting out of what Expo officially calls the managed workflow (everyone else just calls it Expo). An ejected Expo app is referred to as using the bare workflow.

Ejecting means you get all the flexibility of a regular React Native app together with any complexity that brings.

Why would you want to (or not) eject from Expo?

The truth is that by choosing Expo you're trading convenience in some areas for limitations in others. It's like any other framework out there. It comes with tradeoffs.

You get arguably the best developer experience for React Native—no need to fuss with Xcode or Android studio and it's easy to share your work-in-progress with others through the Expo Client app. In short—a lot of really hard things are handled for you.

However, Expo doesn't cover every use case. There are good reasons why you would want to listen to that inner voice chanting...

Eject! Eject! Everything will be possible if I Eject!

So what are some good reasons to eject from Expo?

I need to use an unavailable iOS or Android API

(and I can't wait for the Expo team to add it!)

If you need to use Bluetooth features, In-App Purchases, Google Pay, Apple Pay or WebRTC (audio and video calling) then you simply can't use Expo without ejecting.

The Expo team is constantly working on adding support for API:s that will be useful to everyone. You can follow their progress, vote for and request features on their online feature tracker.

I need to support old versions of Android and iOS

Anyone who will be using your app, including you while developing it, will need to be on at least Android 5 (Lollipop) or iOS 10.

It's important to be able to handle things in the background

Expo does have support for running background services, but not everything will work.

Here's what you definitely won't be able to do:

  • You will NOT be able to play audio or audio from video using the operating system's media controls while your app is not in the foreground, or when it's turned off.
  • You will NOT be able to run code to handle push notifications when your app is closed or in the background.

Here are common things that you will be able to do:

  • Get updates about your user's location using the Background Location API.
  • Fetch or download data in the background using BackgroundFetch

My app download size must be smaller than 20 MB

The smallest size for a non-ejected app bundle will be around 20 MB for iOS and 15 MB for Android. This is because Expo doesn't know which parts of Expo you're actually using. All the code for every Expo feature is included in your app whether you use them or not.

I can't live without my third-party native modules

There are a lot of React Native modules on NPM that require you to run react-native link in your command line. That's another way of saying "Sorry, you can't use this package with Expo".

You may be relying on third-party services, like OneSignal's push notification service, or certain parts of Firebase, like deep-linking and FCM (Firebase Cloud Messaging). If your situation requires a third-party service like this and you can't choose an alternative that doesn't require adding native modules with react-native link then you won't be able to use Expo without ejecting.

Remember that things change, and what wasn't supported at the time of writing might be supported now.

Before letting your inner eject-monster take the lead, make sure to check out if there's a new version of Expo out that just might have added support for the thing you want.