I’ve used Firebase in several Expo apps, mainly for authentication, cloud functions, storage, admin sdk and realtime db. It’s powerful and easy to set up. But, like anything, there are a few bumps along the way.
Since there's too much ground to cover, this guide focuses only on Firebase configuration for native and web. In future articles, I’ll cover specific features with code examples.
Configure Firebase Project
- Go to the https://console.firebase.google.com/
- Create a new project
- Go to Project Settings
- Add a web/android/ios app
- Copy the config object. For Android it's google-services.json, for iOS it's GoogleService-Info.plist.

Setting Firebase in Expo
You'll need react native firebase library. Their getting started guide for expo guide is easy to follow.
Firebase for web integration is more limited than the native one, but you should still have access to the auth, realtime db, storage and functions.
Install dependencies:
npx expo install @react-native-firebase/app expo-build-properties
In your expo app config, this is the part that's important for running native Firebase, and of course having google service files in path:
const config: ExpoConfig = {
ios: {
googleServicesFile: './GoogleService-Info.plist',
bundleIdentifier: 'com.amarjanica.firebaseexpodemo',
supportsTablet: true,
},
android: {
package: 'com.amarjanica.firebaseexpodemo',
googleServicesFile: './google-services.json',
},
plugins: [
'@react-native-firebase/app',
[
'expo-build-properties',
{
"ios": {
"useFrameworks": "static"
}
}
]
],
};
Before running the app on native, it's a good idea to npx expo prebuild --clean
to generate/clean the native directories.
Setting up Firebase in Web
Since Firebase for Web loads differently, it’s best to use environment variables to store credentials. Remember that env variables are embedded at build time, and only those prefixed with EXPO_PUBLIC_
are visible on the web. My .env file looks like:
EXPO_PUBLIC_API_KEY=
EXPO_PUBLIC_AUTH_DOMAIN=
EXPO_PUBLIC_DATABASE_URL=
EXPO_PUBLIC_PROJECT_ID=
EXPO_PUBLIC_STORAGE_BUCKET=
EXPO_PUBLIC_MESSAGING_SENDER_ID=
My module for Firebase web configuration looks like:
import { getApps, initializeApp } from '@firebase/app';
const firebaseConfig = {
apiKey: process.env.EXPO_PUBLIC_API_KEY,
authDomain: process.env.EXPO_PUBLIC_AUTH_DOMAIN,
projectId: process.env.EXPO_PUBLIC_PROJECT_ID,
storageBucket: process.env.EXPO_PUBLIC_STORAGE_BUCKET,
messagingSenderId: process.env.EXPO_PUBLIC_MESSAGING_SENDER_ID,
appId: process.env.EXPO_PUBLIC_APP_ID,
}
const app = getApps().length ? getApps()[0] : initializeApp(firebaseConfig);
export default {
app,
};
If Firebase is initialized multiple times, it throws an error. To prevent this, I saw that the usual practice is to check for for existing apps before initializing.
Configuration is loaded from environment variables and there's no better way to do it because expo-constants are being deprecated in the favor of env variables.
It's ugly, but the alternative would be to hardcode the web configuration that you copy from the Firebase console.
Gluing Native and Firebase Together
I never call react native firebase directly, but through a glue module.
Example of my "glue" module works for expo go and native:
import Constants from 'expo-constants'
const firebase = (Constants.appOwnership === 'expo') ? require('./firebaseWeb').default : require('./firebaseNative').default;
export default firebase;
I also need to have a web specific module - index.web.ts.
export {default} from './firebaseWeb';
If I were to use only the first module, react native firebase would be included in my web bundle. And that would cause issues on the web.
Potential issue with this approach is that web and native modules might not always match in structure, causing interface mismatches. I don't have a better idea, but I know this one works.
Checking if Firebase Works
When checking if Firebase is working correctly, running the app on Android or iOS will immediately fail during build time. Common misconfiguration is a missing google-services.json
for Android or GoogleService-Info.plist
for iOS.
For web, Firebase errors will show up in the browser console.
My demo app checks if the getApps().length > 0
is in running
state, but if Firebase is misconfigured, it will already fail at build time on native or log errors in the console on web.
Youtube: https://youtu.be/6uWL5hxK1NM
GitHub: https://github.com/amarjanica/firebase-expo-demo