Being free from “expo” in React Native apps

Francis Rodrigues
React Brasil
Published in
7 min readMar 17, 2019


Expo allows you to work using an SDK with access to native functionalities easily saving your time whether you desire to create an app in few steps.

The last versions of React Native already come with expo introduced.

What’s the easiest way to remotely share a mobile app that’s still under development without Expo?

This article covers a way to develop without expo for people who decided to keep the project according to their own development strategy.

If you want to share your project in real time, please search about Codeanywhere IDE.

You can also share pieces or the entire React Native code by Codesandbox.
See below an embed code as example:

You can also read about that here:

Expo works fine for me.. So, why would I get rid of the expo?

I made a list with some situations you don’t need expo in your life:

  • to customize the installation;
  • to install custom version of modules (oldest/latest);
  • to use your own React Native modules;
  • to avoid inconsistencies in modules developed by the community;
  • to have more control of project dependencies;
  • to use new ReactJS features;
  • to use your own CI/CD implementation;

First we are showing you how to create a project with expo

Basically you need create-react-native-app.
We’re going to build an app using the commandcreate-react-native-app RNwithExpo. It’ll install everything for you and will run the project pretty easy.

Screenshot of React Native project with expo

Basically, React Native project using expo has this little structure:

Screenshot of React Native expo project structure

It because expo controls all for you. NOT you!

But.. We’d like to have control of the development of our applications.
Now we are going to use two ways to create our project without expo.

Using the react-native-cli command line

The Facebook community developed a way to build React Native applications without expo. You can read more about that below:

Basically, we install a react-native-cli and build a blank/tabs project using the command init , such asreact-native-cli init RNwithoutExpo , where RNwithoutExpo is the name of the project we want to create.

Screenshot of RN project built using `react-native-cli` command line

This project is using the last compatible dependencies between React and React Native. It’s also using babel as JavaScript compiler and jest as JavaScript testing.

Screenshot of the package.json in our React Native project without expo

Running it we’ll see all OK in our project without expo.

Screenshot of RN project running without expo

Ejecting your React Native expo project

Scenario: You are in a situation where your MVP has been approved and you’re seeing in your research on the development strategy, that the application will grow fast, and you need to install many features and testing them as soon as possible to choose the better to your product life cycle.

If you are in this scenario, you want to eject expo of your application and try to work with your own npm packages. You can eject expo running the command npm run eject on the console.

Make sure you’ll choose the option React Native: I’d like a regular React Native project and then rename your project accordingly.

You’ll see a few questions on the console about the ejecting task:

  • How would you like to eject your app? React Native
  • What should your app appear as on a user’s home screen? React Native App
  • What should your Android Studio and Xcode projects be called? ReactNativeApp

Where React Native is the name of your app. Change it to your preference.

Soon after ejecting expo you’ll receive your project like this:

Screenshot of React Native expo project ejected

So I’ve discovered it’s not enough for you to eject expo to be independent of it. You need to do some adjustments in your project, and that’s what I’ll show you below.

First, you’ll start with the package.jsonfile.
You need to remove any reference of expo of your packages.

Screenshot of how to remove any expo reference

After that, remove .expo/ directory, and remove the babel-preset-expo on the babel.config.js file. If you prefer, you can simplify the babel.config.js configuration.

Screenshot about removing expo references in the project

In this step, many developers make the mistake updating React to the last version. This way the application will not run.

Screenshot about most commonly Gradle error in this situation

In this article, I’m not taking into account settings for iOS environment.

The most common error involving Gradle is:

Could not get unknown property 'mergeResourcesProvider' for object of type

But I have the solution to that!

Return React to an earlier version. See the package.json file below:

"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios"
"dependencies": {
"react": "^16.8.3",
"react-native": "^0.59.1"
"devDependencies": {},
"private": true

In the previousandroid/build.gradle build configuration:

Screenshot about previous android/build.gradle configuration

…change some things in the buildscript property:

Screenshot about the new android/build.gradle configuration

An observation: We wont use SDK version 28 (Android 8) to targetSdkVersionproperty to avoid unnecessary configurations. But if you want, below I present a link teaching how to fix the most common error about this version:

So, let’s continuing.. Now change the version of distributionUrl in the android/gradle/wrapper/ file.

Screenshot about the file

So far you didn’t have to install anything

…other than compatible versions of React and React Native. And also you just made a few adjustments to gradle config files.

We are missing to create an important file

We are almost missing to create the index.js file inside our application. :D

Here’s an example of code to the /path-to-project/index.js file.

import { AppRegistry } from "react-native";

import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);

If you have any issues related to Remote JS Debugging, follow the steps below:

Metro Remote JS Debugging

Now we don’t have any JavaScript debug for our expo ejected application.

Screenshot about Metro’s missing in our expo ejected project

This error is very easy to be remedied because it’s very easy to be identified as well.

Error: listen EADDRINUSE :::8081
at Server.setupListenHandle [as _listen2] (net.js:1345:14)
at listenInCluster (net.js:1386:12)
at Server.listen (net.js:1474:7)
at Promise (/home/paneladm/projects/react-native-apps/RNwithExpo/node_modules/metro/src/index.js:253:20)

So we need to install metro-react-native-babel-preset package as devDependencies

npm i -D metro-react-native-babel-preset

and mention it in the babel.config.js file, something like this:

presets: ["module:metro-react-native-babel-preset"]

I added an extra Text line followed by some style to test the Live Reload and all OK now.

Screenshot of the final project working

That’s it! =)
Now you have the control over your project!

I created a github repository about the project worked on this article.

That’s it! :D

Unable to load script from assets

If you have any problems with the Android bundle it’s because the assets folder doesn’t exist. To solve that issue, follow the instructions at this link:

I hope I’ve helped those with doubts on how to create applications in the new versions of React Native without using these magic libs.

Any question, don’t hesitate to ask me.



Francis Rodrigues
React Brasil

Software Engineer | Tech Writer