Introduction

If you are building a React Native application, you need to make an early choice if you want to kickstart development with Expo. There is a lot of material that treats Expo versus React Native as a list of pros and cons; in reality, a lot of material is outdated, especially because Expo has dramatically changed over the last few years. Today, it's not React Native versus Expo—it is more do you want to start with Expo.

Below, we’ll discuss which framework is ideal for which users; or, more specifically, why developers should default to Expo unless an objection applies to them.

Of course, we at Retool believe that developers shouldn’t code mobile apps from scratch for internal use cases—such as inventory management, customer success, or general database management. Learn more about Retool Mobile if you are starting on a mobile app project for your internal teams; otherwise, learn below how modern-day Expo CLI fares against stock React Native CLI.

Background

React Native and Expo have one of the more curious relationships in the vast, ever-stretching lands of developer tooling.

Let’s first cruise through some quick history. In 2015, Meta (formerly Facebook) released the first version of React Native—a UI framework that could compile React/Javascript code into native iOS (Obj-C + Swift) and Android (Java + Kotlin) code. Then, shortly after, Expo emerged—a toolkit + framework designed to streamline developing React Native applications.

Sure, core frameworks having popular extended frameworks are commonplace. For instance, today’s developers often use NextJS in lieu of stock React. Same could be said about ExpressJS in its relationship with Node. But Expo is a bit special. While managed by an independent startup, Expo CLI is the recommended environment by the official React Native team.

Yes, that’s right. The React Native docs believes that, by default, developers should choose Expo CLI over their own React Native CLI. Why? Well, React Native CLI and Expo CLI aren’t exactly competitors; rather, they are two techniques vying for the same goal. Specifically, Expo solves some tricky barriers that are exclusive to mobile development, but its techniques are too opinionated for a broad framework like React Native.

However, in the last 24 months, Expo has released some dramatic changes, many of which bridge the gap between itself and React Native CLI. Today, the question is more “Why not Expo?”.

Part 1: Refresher on Expo CLI and React Native CLI

How React Native works

React Native compiles Javascript into two codebases—a Swift, Objective-C codebase and a Java, Kotlin codebase. Respectively, those two intermediary codebases are then natively compiled into iOS and Android binaries, usable on smartphones, smart watches, smart tablets, etc.

React Native compiles into Swift / Objective-C / Kotlin / Java, but still requires XCode (iOS) and Android Studio to compile the native code into mobile binaries. XCode and Android Studio enable developers to boot an app onto a real plugged-in iPhone or Android device. They are also both infamous for flirting with “Application Not Responding” error messages.

React Native was born out of the popularity of React, arguably the most successful Javascript framework ever (no offense to JQuery or Vue stans). Some might argue that React Native apps are often more native than native apps because they tend to rely less on web-views.

How Expo works

Expo flipped React Native development on its head by replacing how compilation, deployment, and testing worked. In particular, Expo features four major components:

  • Expo—an open-source framework for building React Native apps with consolidated logic for both iOS and Android.
  • Expo Go—an open-source app publicly available on the App Store and Play Store that makes testing apps easy via a scannable QR code.
  • Expo Dev Clients—an open-source framework to build a personalized Expo Go application in case Expo Go grows incompatible with certain mobile features.
  • EAS, or Expo Application Services—a set of freemium services by Expo Inc that build apps on Expo-managed devices and submit them to the app store. EAS isn’t open-source and is Expo’s primary business model.

You’ll soon notice a familiar trend—certain features are technically compatible with Expo, but not Expo Go. And, originally, not being compatible with Expo Go was synonymous with not being compatible with Expo. Today, however, Expo Dev Clients and EAS have expanded Expo’s horizons.

How does Expo Go work?

Expo Go can be described as a shell app. It’s available on the official mobile app store and includes all the core Expo SDK libraries (later discussed). Using a QR code to facilitate a link, Expo Go runs an Expo project by importing a build over a LAN or localhost connection. In the case of firewalls to prevent LAN connections, ngrok-powered internet tunneling could be used instead.

After scanning the QR code, Expo Go connects to a development machine’s local Expo dev server and requests a manifest.json. Then, Expo Go downloads a Javascript bundle and any assets needed to render the React Native app.

When changes are saved on the local development machine, Expo Go will automatically load them over-the-air. To many React Native developers, this is magic that was previously missing via XCode’s cord-required booting scheme.

A common misconception surrounding Expo Go is that it’s just a glorified web-view. Instead, Expo Go is executing the Javascript bundle utilizing the Hermes Javascript engine which is optimized for React Native.

However, Expo Go cannot render any React Native app fully. Specifically, while Expo Go can render any arbitrary React Native app, the custom native code won't be available. Because those libraries are not available in the Expo Go build, the code that invokes them will fault.

How does EAS work?

EAS or Expo Application Service is split into EAS Build and EAS Submit.

  • EAS Build compiles your React Native codebase on Expo public servers into production builds for iOS and Android. It also handles signing the build—a digital signature from a developer that an app’s code hasn’t been augmented since it was last submitted, which Expo facilitates programmatically.
  • EAS Submit, meanwhile, enables developers to easily submit their app to the Play Store or App Store after it’s built.

Both of these steps could be combined into a single command, which is great for teams that want to frequently make incremental updates to their application.

While EAS has a free tier, EAS is a paid service with enterprise-friendly tiers. Expo enables users to also customize their build resources for more memory-starving builds.

How to think about Expo versus React Native

By default, you should choose Expo. Simply, Expo is easier to use, faster to test, and produces neater code. There are other arguments for using Expo, but the aforementioned three tend to be the biggest factors.

But, as with any default, there are exceptions. And when Expo was first started, there were many, many objections. Some remain true today. Others have been erased by Expo’s recent updates.

For the remainder of this guide, we’ll travel through the main objections to using Expo—outdated or not—and address if they still apply and to whom they impact.

Part 2: The Historical Objections to Expo

PS: The biggest objection, by a wide margin, is the first.

Common Objection #1: Expo doesn’t enable the use of native libraries

Today’s Verdict: Halfway-true

Originally, Expo was designed to build products using strictly React Native code, with no support for native libraries like CocoaPods. This contrasted with the stock React Native CLI where you could include native libraries and interface with them.

Three years ago, saying Expo was incompatible with native libraries was unquestionably true. But today, it’s definitely false. Rather, certain components of Expo’s tooling—notably Expo Go—remain incompatible with native libraries, but new products—like EAS—are fully compatible.

Let’s walk through how.

Why is Expo Go Incompatible with Native Libraries?

When React Native interfaces with native libraries, it includes native libraries in the app’s build and interfaces with them similar to how someone would interface with an API. However, Expo Go is an already-built app that simply executes a Javascript bundle via the Hermes engine—any native library dependencies aren’t available in the Expo Go product.

If your only reason for using Expo is to take advantage of Expo Go, then yes, Expo doesn’t work with native libraries. But two things—Expo SDK libraries and Expo Dev Clients—alleviate this limitation.

What are Expo SDK Libraries?

The main reason that developers often have to use third-party libraries is because React Native’s core libraries are fairly limited. However, those third-party libraries invoke native code… which brings us back to the prior constraint.

To account for this, Expo has released the Expo SDK libraries which enable common mobile functionality such as the camera, calendar, contacts, video, audio, barcodes, etc. Even better, these custom SDK libraries’ underlying native libraries come included in the Expo Go build—so they work with Expo Go perfectly.

There is a pro and a con to this approach.

The pro is that Expo SDK libraries are form-fitted for Expo’s design language. Code that utilizes these libraries will feel consistent and readable. Often dealing with third-party libraries that invoke native code is the bane of a React Native engineer’s existence. Expo SDK libraries Thanos-snaps that frustration away.

The con, however, is that Expo’s SDK libraries don’t cover every mobile feature nor do they cover every customizable aspect of each feature. If an app requires a fairly custom implementation of a certain native SDK, or perhaps a niche function not covered by its respective Expo SDK library, then it’s back to square one.

But that’s where Expo Dev Clients come in.

What are Expo Dev Clients?

Expo Go is an open-source app. So, it isn’t too surprising that Expo has made it easy to extend the Expo Go product into a custom shell app. That’s exactly what the expo-dev-client package is—a template of Expo Go to be personalized for any arbitrary React Native project.

The caveat is in the distribution. Expo Go’s distribution is handled by Expo—you can install the latest version of Expo Go on the App Store or Play Store. But for Expo Dev Clients, you’ll need to register your app with Testflight and manually approve developer devices that are allowed access to it. That legwork does cut into Expo’s value proposition of expediting development; however, this is a game-changer for companies that want to start with Expo Go yet retain the option to personalize that experience should they need to.

What was Expo Eject?

Prior to Expo Dev Clients, developers would eject their Expo apps. Ejecting involved exporting an Expo project as a stock React Native project known as a bare app. However, once native libraries were added to the bare app, it could only be compiled utilizing XCode or Android Studio, not the original Expo compiler (known as Turtle). Some enterprise clients would write a script that would merge an ejected app with additional code linking native libraries, and then utilize XCode or Android Studio to compile the final product.

This is no longer a valid strategy today.

Expo Prebuild

Nowadays, the new EAS Build service can compile any React Native app, including apps with native libraries. It accomplishes this by prebuilding the app—which generates the native source code—and then running EAS Build to build the project.

Admirably, this flow still enables developers to craft applications—even applications with native code—without relying on Expo’s freemium EAS service. Hypothetically, developers could craft an Expo Dev Client to test an Expo project on the fly, then just run Expo Prebuild to generate native source code, and finally utilize XCode or Android Studio to compile the final product.

Regardless, EAS has some big advantages. It’s easier to use over XCode and Android Studio. It relies on public machines, not developer CPU and RAM.

Common Objection #2: Expo doesn’t support in-app purchases

Today’s Verdict: Also halfway-true

In-app purchases are a major feature when it comes to mobile apps, particularly iOS. You might’ve read about the infamous Fortnite (Epic Games) versus App Store lawsuit. For the most part, Apple won the suit, forcing developers to utilize Apple’s native in-app purchases library for any credit card transactions, of which it exacts a 30% cut.

Technically, Expo has a library for supporting in-app purchases. It interfaces with the Google Play Billing and StoreKit frameworks on Android and iOS respectively. But development on this front is currently paused in favor of other projects, particularly because RevenueCat solves the problem fairly well.

RevenueCat—a third-party solution for streamlining in-app purchases by wrapping around StoreKit and Google Play Billing—has an Expo plugin. Amongst active developers in the Expo community, it is evidently popular. The first $10,000 in monthly revenue is free on RevenueCat. Even afterward, RevenueCat’s fees are rather negligible compared to Apple and Google’s massive rake. For a lot of app developers, that’s a good trade.

Regardless, these approaches still do away with Expo Go. Developers need to utilize an Expo Dev Client for testing these packages Expo-style.

Common Objection #3: Expo’s build servers have limited RAM limits

Today’s Verdict: False

Because EAS Build is a hosted service that builds projects on the cloud, it used to have an arbitrary build limitation of 12GB RAM. However, Expo has since extended support for custom build resources.

Common Objection #4: Expo apps are heavyweight

Today’s Verdict: False.

Previously, Expo’s old build service originally compiled an entire Expo Go app and then injected the Javascript bundle. This meant tons of native libraries and packages that weren’t used were also included.

However, today, Expo Prebuild creates code that is only relevant to the project, before handing those files to EAS or XCode / Android Studio to complete the compilation. As a result, Expo projects nowadays are not heavyweight relative to other React Native projects.

Common Objection #5: Apps cannot leverage WebRTC, the main video / audio calls framework

Today’s Verdict: Mostly False.

WebRTC can be added to an Expo project with a config plugin. The config plugin has support for both camera and microphone permissions. Obviously, this also requires an Expo Dev Client and is incompatible with Expo Go.


In summary, developers should choose Expo, but if they are utilizing native features, they must:

  • Use an Expo SDK library to address any needed native features, or
  • Create an Expo Dev Client and handling distribution is a better internal workflow than utilizing XCode, which is likely if the developers commit to EAS.

Overall, Expo dramatically reduces the amount of stress to develop React Native apps. While its clever, over-the-air techniques dramatically go against the grain of many iOS and Android design principles, Expo has found ways to strike a balance between expedited development and extensibility.

And as always, if you’re building apps for your internal teams, check out Retool Mobile, which can help you launch production-ready native apps in a few hours with just JavaScript and SQL.