How to integrate react-native-firebase with Expo

Over a year ago I wrote an article about a kind of hacky way to use react-native-firebase in Expo app. But things have changed significantly since then. In this article, I’m going to show you the new, much easier way to do this.
This is also a getting started guide for new features that Expo has released recently.

TL;DR Scroll down, there’s a tutorial down below. 😉

A long time ago…

Since I didn’t want to opt out of Expo Go for development, I came up with the idea of using Expo-compatible Firebase Web (JavaScript) SDK in development and, at the same time, keeping ejected native projects with the more performant and fully featured native SDKs installed using react-native-firebase. I had a common JS codebase, which deduced in which environment it runs (Expo Go or bare RN app) and automatically switched to the correct Firebase backend.

My solution was working, but it was very cumbersome to maintain in further project stages. I had to take care of both bare and managed app separately. Things like permissions, app icon, or splash screen required separate steps for Android, iOS and managed app. Nightmare.

The new, right way!

Ok, I’m hyped about that new wonderful Expo stuff, but what does it mean in the context of my Firebase integration? Let me explain briefly:

  • I’m building my app using a semi-managed workflow. That is: I do everything like it was managed workflow, but I also have some JavaScript code, which calls native libraries like react-native-firebase.
  • Instead of the Expo Go app, I’m using my custom development client with react-native-firebase bundled with it.
  • Each time I need a native change, e.g. install a native library, I rebuild my Dev Client using either EAS Build or locally using expo run:android / expo run:ios. You can read more about these commands in this blog post.
  • If a native library requires custom configuration — e.g. adding some code or modifying Android manifest, that configuration is applied during prebuilding phase thanks to Config Plugins.
  • A prebuild is actually very similar to eject, but its name no longer sounds like it’s a one-way ticket. It’s designed to be run multiple times, without losing the possibility to use Expo managed features.

The whole process has been explained more deeply in the blog series: Expo Managed Workflow in 2021 — part one, part two.

Cool, but… how to make it work? 🤔 A detailed step-by-step guide is here!

First of all, ensure that you have the latest expo-cli installed. You can quickly do it with yarn global add expo-cli.

1. Start a project
If you have an existing managed Expo project, you can use it here, but please git commit first to make a checkpoint. I wouldn’t recommend using bare projects since prebuilding has undefined behavior on existing native projects! This doesn’t mean that you can’t use development clients in bare apps — you just have to install it manually.

Tip: When creating new project, you can run npx create-react-native-app -t with-dev-client to have a custom development client already set up. However, I decided to show more manual/universal solution, which should also work for existing projects.

I chose to start a new managed project and selected a blank (TypeScript) template:

Creating an app with expo init

2. Set up a development client
We want to develop our app with a custom development client. In order to do that, install a proper module:

expo install expo-dev-client

This package makes your debug native configuration build a custom development client. The release configuration remains unchanged; it builds a production app without the expo-dev-client code included, aside from a few header files.

Since you’ll be building your app anyway, you can skip this step for now and come back later. If so, jump straight to Firebase installation.

When running commands from below for the first time, you’ll be asked for Android Application ID (package name) and iOS Bundle Identifier, unless you have provided them earlier in app.json.

Try to build and start your dev client by running either expo run:android or expo run:ios. Alternatively, you can also use EAS Build to do the job, but unless you created a project from with-dev-client template, you’ll have to configure eas.json yourself (you can use eas build:configure to automate this).

Note: expo run commands start Metro bundler by default unless --no-bundler flag is provided. To start the bundler without triggering the build process, use expo start --dev-client.

If everything goes well, after a short while you should see your custom development client running on an emulator.

A running Development Client

3. Install Firebase
Now you can install react-native-firebase JS libraries of your choice. In my app I want to use the Firestore module:

yarn add @react-native-firebase/app @react-native-firebase/firestore

In the meantime, you need to open the Firebase Console and create Android and iOS apps for your project. You’ll be asked about Android App ID and iOS Bundle Identifier. You have to provide the same values that you typed in earlier.
Please download the google-services.json and GoogleServices-Info.plist — we’re going to need them in a moment.

Are we ready? Almost. When you visit the react-native-firebase website, you can see that installation steps require native changes. This is where config plugins unleash their power. A plugin’s purpose is to apply native configuration changes each time when building with EAS Build or running expo prebuild / expo run, without bothering you with native stuff.

Fortunately, I’ve prepared a ready-to-go plugin, which does all the necessary configuration for react-native-firebase. If this didn’t exist, you’d need to read the config plugins guide, but because it does, all you have to do is to install a package:

expo install with-rn-firebase

By default, it looks for Google-Services files in the firebase/ directory inside project root, so please put the downloaded google-services.json and GoogleServices-Info.plist there. Alternatively, you can configure custom paths for the plugin in app.json.

The plugin idea doesn’t only apply to Firebase; it applies to any native library that requires additional configuration after linking. Since the config plugins API is pretty new, there aren’t yet many libraries that support config plugins. That’s a large area for open-source contributors. You are very welcome to help developing config plugins for your favourite libraries!

4. Run your app
Now, all that’s left to do is to build your app again (EAS Build / expo run) and you are free to start using Firebase!

A quick example of Firestore usage in an Expo app

This way you have set up react-native-firebase in your own custom Expo Go… I mean development client 😅. Of course, the stuff described in this article is only the tip of an iceberg. There are many more awesome features, including a customizable developer menu. You may also want to share your custom dev client with your team/friends, or even automate it with the CI. You can learn more about all that stuff in Expo Docs.

Enthusiast of electronics and all kinds of software development — from web apps to embedded systems. Expo open-source contributor at Software Mansion.