Technical Documentation: invertase/react-native-firebase
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (README.md)
React Native Firebase is a collection of official React Native modules connecting you to Firebase services; each module is a light-weight JavaScript layer connecting you to the native Firebase SDKs for both iOS and Android.
React Native Firebase is built with four key principles in mind;
- 🧪 Well tested
- every module is extensively tested to >95% coverage
- 👁 Well typed
- first class support for Typescript included
- 📄 Well documented
- full reference & installation documentation alongside detailed guides and FAQs
- 🔥 Mirrors official Firebase Web SDK
- functions as a drop-in replacement for the Firebase Web SDK in React Native
- maximizes cross-platform code re-usability e.g. re-using code on web platforms
Firebase Modules
This is the root of the mono-repo for React Native Firebase, if you're looking for a specific package please select the package link from below.
The main package that you interface with is App (@react-native-firebase/app)
Documentation
Looking for the Version 5 documentation? View legacy documentation.
Contributing
License
- See LICENSE
Index (`docs/index.mdx`)
title: React Native Firebase next: /migrating-to-v22
React Native Firebase has begun to deprecate the namespaced API (i.e firebase-js-sdk
< v9chaining API). React Native Firebase will be moving to the modular API (i.e. firebase-js-sdk>= v9) in the next major release. See migration guide for more information.
React Native Firebase is the officially recommended collection of packages that brings React Native support for all Firebase services on both Android and iOS apps.
React Native Firebase fully supports React Native apps built using React Native CLI or using Expo.
Source: github.com/invertase/react-native-firebase · Packages: npmjs.com/org/react-native-firebase (@react-native-firebase/app, @react-native-firebase/auth, @react-native-firebase/firestore, and one package per Firebase service)
React Native Firebase vs firebase-js-sdk
Use React Native Firebase (this project) when your app runs on Android and/or iOS: it wraps the native Firebase Android and iOS SDKs directly, so you get capabilities the web SDK cannot provide on mobile, like native app analytics, background/killed-state push notifications, and native Crashlytics crash reports.
Use the plain firebase-js-sdk when you're targeting web, React Native Web, or another JavaScript-only environment with no native module support. React Native Firebase already falls back to firebase-js-sdk on those platforms; see Other / Web below.
Prerequisites
Before getting started, the documentation assumes you are able to create a project with React Native and that you have an active Firebase project.
If you do not meet these prerequisites, follow the links below:
Additionally, current versions of firebase-ios-sdk have a minimum Xcode requirement of 26.2 and the Swift 6.2.3+ toolchain, which implies a minimum macOS version of 15 (Xcode 26.2 is supported on macOS 15). See Apple's Upcoming SDK minimum requirements for details.
Installation for Expo projects
Integration with Expo is possible when using a development build. You can configure the project via config plugins or manually configure the native projects yourself (the "bare workflow").
NOTE: React Native Firebase cannot be used in the pre-compiled Expo Go app because React Native Firebase uses native code that is not compiled into Expo Go.
Warning: If you are using
expo-dev-client, native crashes (such as those triggered bycrash(getCrashlytics())) will not be reported to Firebase Crashlytics during development. This is becauseexpo-dev-clientprovides a custom error overlay that catches and displays errors before they are sent to Firebase. To test native crash reporting, you must removeexpo-dev-clientand run your app in a standard release or debug build without the custom error overlay.
To create a new Expo project, see the Get started guide in Expo documentation.
Install React Native Firebase modules
To install React Native Firebase's base app module, use the command npx expo install @react-native-firebase/app.
Similarly you can install other React Native Firebase modules such as for Authentication and Crashlytics: npx expo install @react-native-firebase/auth @react-native-firebase/crashlytics.
Configure React Native Firebase modules
The recommended approach to configure React Native Firebase is to use Expo Config Plugins. You will add React Native Firebase modules to the plugins array of your app.json or app.config.js. See the note below to determine which modules require Config Plugin configurations.
If you are instead manually adjusting your Android and iOS projects (this is not recommended), follow the same instructions as React Native CLI projects.
To enable Firebase on the native Android and iOS platforms, create and download Service Account files for each platform from your Firebase project. Then provide paths to the downloaded google-services.json and GoogleService-Info.plist files in the following app.json fields: expo.android.googleServicesFile and expo.ios.googleServicesFile. See the example configuration below.
For iOS, React Native Firebase resolves the Firebase Apple SDK with Swift Package Manager by default on React Native 0.75+. SPM requires dynamic frameworks — configure expo-build-properties with "useFrameworks": "dynamic". See the example configuration below.
The following is an example app.json to enable the React Native Firebase modules App, Auth and Crashlytics, that specifies the Service Account files for both mobile platforms, and that sets the application ID to the example value of com.mycorp.myapp (change to match your own).
You will need to add a plugin entry for each react-native-firebase module you use that defines an Expo config plugin - these are documented on the specific module install pages.
{
"expo": {
"android": {
"googleServicesFile": "./google-services.json",
"package": "com.mycorp.myapp"
},
"ios": {
"googleServicesFile": "./GoogleService-Info.plist",
"bundleIdentifier": "com.mycorp.myapp"
},
"plugins": [
"@react-native-firebase/app",
"@react-native-firebase/auth",
"@react-native-firebase/crashlytics",
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "dynamic"
}
}
]
]
}
}Listing a module in the Config Plugins (the
"plugins"array in the JSON above) is only required for React Native Firebase modules that involve native installation steps - e.g. modifying the Xcode project,Podfile,build.gradle,AndroidManifest.xmletc. React Native Firebase modules without native steps will work out of the box; no"plugins"entry is required. Not all modules have Expo Config Plugins provided yet. A React Native Firebase module has Config Plugin support if it contains anapp.plugin.jsfile in its package directory (e.g.node_modules/@react-native-firebase/app/app.plugin.js).
If you use @react-native-firebase/analytics with Expo, including EAS Build, and want to configure iOS Analytics Podfile flags, add the Analytics config plugin with the relevant iOS options:
[
"@react-native-firebase/analytics",
{
"ios": {
"withoutAdIdSupport": true,
"googleAppMeasurementOnDeviceConversion": true
}
}
]The withoutAdIdSupport option adds $RNFirebaseAnalyticsWithoutAdIdSupport = true to opt out of iOS Ad ID support. The googleAppMeasurementOnDeviceConversion option adds $RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true to include Google Analytics on-device conversion measurement support. You may omit either option if it is not needed.
Dynamic frameworks (required)
Firebase Apple SDK 13+ is SPM-only. Do not pass disableSPM: true or use static frameworks with RNFB SPM mode — pod install / prebuild will fail. Set "useFrameworks": "dynamic" via expo-build-properties. See iOS SPM Support.
Local app compilation
If you are compiling your app locally, run npx expo prebuild --clean to generate the native project directories. Then, follow the local app compilation steps described in Local app development guide in Expo docs. If you prefer using a build service, refer to EAS Build.
Note: if you have already installed an Expo development build (using something like npx expo run after doing the --prebuild local development steps...) before installing react-native-firebase, then you must uninstall it first as it will not contain the react-native-firebase native modules and you will get errors with RNFBAppModule not found etc. If so, uninstall the previous development build, do a clean build using npx expo prebuild --clean, and then attempt npx expo run: again.
Expo Tools for VSCode
If you are using the Expo Tools VSCode extension, the IntelliSense will display a list of available plugins when editing the plugins section of app.json.
Installation for React Native CLI (non-Expo) projects
Installing React Native Firebase to a RN CLI project requires a few steps; installing the NPM module, adding the Firebase config files &
rebuilding your application.
1. Install via NPM
Install the React Native Firebase "app" module to the root of your React Native project with NPM or Yarn:
# Using npm
npm install --save @react-native-firebase/app
# Using Yarn
yarn add @react-native-firebase/appThe @react-native-firebase/app module must be installed before using any other Firebase service.
2. React Native CLI - Android Setup
To allow the Android app to securely connect to your Firebase project, a configuration file must be downloaded and added
to your project.
Generating Android credentials
On the Firebase console, add a new Android application and enter your projects details. The "Android package name" must match your
local projects package name which can be found inside of the namespace field in /android/app/build.gradle, or in themanifest tag within the /android/app/src/main/AndroidManifest.xml file within your project for projects using android gradle plugin v7 and below
The debug signing certificate is optional to use Firebase with your app, but is required for Invites and Phone Authentication.
To generate a certificate runcd android && ./gradlew signingReport. This generates two variant keys.
You have to copy both 'SHA1' and 'SHA-256' keys that belong to the 'debugAndroidTest' variant key option.
Then, you can add those keys to the 'SHA certificate fingerprints' on your app in Firebase console.
Download the google-services.json file and place it inside of your project at the following location: /android/app/google-services.json.
Configure Firebase with Android credentials
To allow Firebase on Android to use the credentials, the google-services plugin must be enabled on the project. This requires modification to two
files in the Android directory.
First, add the google-services plugin as a dependency inside of your /android/build.gradle file:
buildscript {
dependencies {
// ... other dependencies
classpath 'com.google.gms:google-services:4.5.0'
// Add me --- /\
}
}Lastly, execute the plugin by adding the following to your /android/app/build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services' // <- Add this line3. React Native CLI - iOS Setup
To allow the iOS app to securely connect to your Firebase project, a configuration file must be downloaded and added to your project, and you must enable frameworks in CocoaPods
Generating iOS credentials
On the Firebase console, add a new iOS application and enter your projects details. The "iOS bundle ID" must match your
local project bundle ID. The bundle ID can be found within the "General" tab when opening the project with Xcode.
Download the GoogleService-Info.plist file.
Using Xcode, open the projects /ios/{projectName}.xcodeproj file (or /ios/{projectName}.xcworkspace if using Pods).
Right click on the project name and "Add files" to the project, as demonstrated below:
Select the downloaded GoogleService-Info.plist file from your computer, and ensure the "Copy items if needed" checkbox is enabled.
Configure Firebase with iOS credentials (react-native 0.77+)
To allow Firebase on iOS to use the credentials, the Firebase iOS SDK must be configured during the bootstrap phase of your application.
To do this, open your /ios/{projectName}/AppDelegate.swift file and add the following:
At the top of the file, import the Firebase SDK right after 'import ReactAppDependencyProvider':
import FirebaseWithin your existing application method, add the following to the top of the method:
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Add me --- \/
FirebaseApp.configure()
// Add me --- /\
// ...
}Configure Firebase with iOS credentials (react-native < 0.77)
To allow Firebase on iOS to use the credentials, the Firebase iOS SDK must be configured during the bootstrap phase of your application.
To do this, open your /ios/{projectName}/AppDelegate.mm file (or AppDelegate.m if on older react-native), and add the following:
At the top of the file, import the Firebase SDK right after '#import "AppDelegate.h"':
#import <Firebase.h>Within your existing didFinishLaunchingWithOptions method, add the following to the top of the method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Add me --- \/
[FIRApp configure];
// Add me --- /\
// ...
}Altering CocoaPods to use frameworks
Beginning with firebase-ios-sdk v9+ (react-native-firebase v15+) you must tell CocoaPods to use frameworks. On React Native 0.75+, React Native Firebase resolves the Firebase Apple SDK with Swift Package Manager by default, which requires dynamic linkage.
Open the file ./ios/Podfile and add this line inside your targets (right before the use_react_native line in current react-native releases that calls the react native Podfile function to get the native modules config):
use_frameworks! :linkage => :dynamicDo not combine RNFB's default SPM mode with use_frameworks! :linkage => :static — pod install rejects that combination. Full requirements, Expo notes, and troubleshooting are in iOS SPM Support.
Firebase Apple SDK 13+ cannot use CocoaPods Firebase or $RNFirebaseDisableSPM. Stay on dynamic SPM linkage. See iOS SPM Support.
Note:
use_frameworksis not compatible with Flipper. Flipper is deprecated in the React Native community; if your Podfile still references:flipper_configuration, remove or comment it out.
4. Autolinking & rebuilding
Once the above steps have been completed, the React Native Firebase library must be linked to your project and your application needs to be rebuilt.
Users on React Native 0.60+ automatically have access to "autolinking",
requiring no further manual installation steps. To automatically link the package, rebuild your project:
# Android apps
npx react-native run-android
# iOS apps
cd ios/
pod install --repo-update
cd ..
npx react-native run-iosOnce successfully linked and rebuilt, your application will be connected to Firebase using the @react-native-firebase/app module. This module does not provide much functionality, therefore to use other Firebase services, each of the modules for the individual Firebase services need installing separately.
Other / Web
If you are using the firebase-js-sdk fallback support for web or "other" platforms then you must initialize Firebase dynamically by calling initializeApp.
However, you only want to do this for the web platform. For non-web / native apps the "default" firebase app instance will already be configured by the native google-services.json / GoogleServices-Info.plist files as mentioned above.
At some point during your application's bootstrap processes, initialize firebase like this:
import { getApp, initializeApp } from '@react-native-firebase/app';
// web requires dynamic initialization on web prior to using firebase
if (Platform.OS === 'web') {
const firebaseConfig = {
// ... config items pasted from firebase console for your web app here
};
initializeApp(firebaseConfig);
}
// ...now throughout your app, use firebase APIs normally, for example:
const firebaseApp = getApp();Miscellaneous
Overriding Native SDK Versions
React Native Firebase internally sets the versions of the native SDKs which each module uses. Each release of the library
is tested against a fixed set of SDK versions (e.g. Firebase SDKs), allowing us to be confident that every feature the
library supports is working as expected.
Sometimes it's required to change these versions to play nicely with other React Native libraries or to work around temporary build failures; therefore we allow
manually overriding these native SDK versions.
Using your own SDK versions is not recommended and not supported as it can lead to unexpected build failures when new react-native-firebase versions are released that expect to use new SDK versions. Proceed with caution and remove these overrides as soon as possible when no longer needed.
Android
Within your projects /android/build.gradle file, provide your own versions by specifying any of the following options shown below:
project.ext {
set('react-native', [
versions: [
// Overriding Build/Android SDK Versions if desired
android : [
minSdk : 24,
targetSdk : 34,
compileSdk: 34,
],
// Overriding Library SDK Versions if desired
firebase: [
// Override Firebase SDK Version
bom : "35.0.0"
],
],
])
}Once changed, rebuild your application with npx react-native run-android.
iOS
Firebase Apple SDK 13+ is resolved via Swift Package Manager. $FirebaseSDKVersion and FIREBASE_SDK_VERSION override the SPM exact pin (same version string RNFB passes to firebase-ios-sdk SPM) — they are not CocoaPods trunk version selectors.
Open your projects /ios/Podfile and add any of the globals shown below to the top of the file:
# Override Firebase Apple SDK SPM exact pin if desired (see /ios-spm)
$FirebaseSDKVersion = '13.0.0'Once changed, reinstall your projects pods via pod install and rebuild your project with npx react-native run-ios.
Alternatively, if you cannot edit the Podfile easily (as when using Expo), you may add the environment variable FIREBASE_SDK_VERSION=13.0.0 (or whatever SPM exact pin you need) to the command line that installs pods. For example FIREBASE_SDK_VERSION=13.0.0 yarn expo prebuild --clean
Android Performance
On Android, React Native Firebase uses thread pool executor to provide improved performance and managed resources.
To increase throughput, you can tune the thread pool executor via firebase.json file within the root of your project:
// <project-root>/firebase.json
{
"react-native": {
"android_task_executor_maximum_pool_size": 10,
"android_task_executor_keep_alive_seconds": 3
}
}| Key | Description |
|---|---|
android_task_executor_maximum_pool_size |
Maximum pool size of ThreadPoolExecutor. Defaults to 1. Larger values typically improve performance when executing large numbers of asynchronous tasks, e.g. Firestore queries. Setting this value to 0 completely disables the pooled executor and all tasks execute in serial per module. |
android_task_executor_keep_alive_seconds |
Keep-alive time of ThreadPoolExecutor, in seconds. Defaults to 3. Excess threads in the pool executor will be terminated if they have been idle for more than the keep-alive time. This value doesn't have any effect when the maximum pool size is lower than 2. |
Reference Api Readme (`docs/reference-api-readme.md`)
API reference
This site documents the TypeScript and JavaScript APIs for the react-native-firebase packages published on npm under the @react-native-firebase/* scope.
The app module is required; all other modules are optional peer packages. Use the sidebar to open each package. Cross-package types (for example FirebaseApp) link between modules when they are part of this documentation build.
For guides and setup, see the main documentation.
Releases Index (`docs/releases/index.mdx`)
title: Release notes
Starting from version 10.0.0, React Native Firebase packages share a single common version, with aggregated release notes available:
From version v6.5.0 until 10.0.0; all React Native Firebase packages were independently versioned with individually generated release notes:
| Package | ||
|---|---|---|
| Analytics | View Release Notes » | |
| App | View Release Notes » | |
| App Check | View Release Notes » | |
| App Distribution | View Release Notes » | |
| Authentication | View Release Notes » | |
| Cloud Firestore | View Release Notes » | |
| Cloud Functions | View Release Notes » | |
| Cloud Messaging | View Release Notes » | |
| Cloud Storage | View Release Notes » | |
| Crashlytics | View Release Notes » | |
| In-app Messaging | View Release Notes » | |
| Installations | View Release Notes » | |
| Performance Monitoring | View Release Notes » | |
| Realtime Database | View Release Notes » | |
| Remote Config | View Release Notes » |
To view release notes for versions prior to v6.5.0 see the table below.
| Version | |
|---|---|
| v6.4.0 | View Release Notes » |
| v6.3.0 | View Release Notes » |
| v6.2.0 | View Release Notes » |
| v6.1.0 | View Release Notes » |
| v6.0.3 | View Release Notes » |
| v6.0.2 | View Release Notes » |
| v6.0.1 | View Release Notes » |
| v6.0.0 | View Release Notes » |
Ai Usage Index (`docs/ai/usage/index.mdx`)
title: AI Logic next: /analytics/usage previous: /faqs-and-tips
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the ai module
yarn add @react-native-firebase/aiPlatform support
| Platforms | Android, iOS, Web (firebase-js-sdk interop) |
| New Architecture | Not required — pure JavaScript package with no native TurboModule. |
What does it do
Firebase AI Logic gives you access to the latest generative AI models from Google.
If you need to call the Gemini API directly from your mobile or web app — rather than server-side — you can use the Firebase AI Logic client SDKs. These client SDKs are built specifically for use with mobile and web apps, offering security options against unauthorized clients as well as integrations with other Firebase services.
Usage
Generate text from text-only input
You can call the Gemini API with input that includes only text. For these calls, you need to use a model that supports text-only prompts (like Gemini 3.1 Flash-Lite).
Use generateContent() which waits for the entire response before returning.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="generate content"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, { model: 'gemini-3.1-flash-lite' });
const result = await model.generateContent('What is 2 + 2?');
console.log(result.response.text());
}}
/>
</View>
);
}Use generateContentStream() if you wish to stream the response.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="generate content stream"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, { model: 'gemini-3.1-flash-lite' });
const result = await model.generateContentStream('Write a short poem');
let text = '';
for await (const chunk of result.stream) {
const chunkText = chunk.text();
text += chunkText;
}
console.log(text);
const response = await result.response;
// Optional: use metadata (e.g. groundingMetadata when grounding is enabled)
if (response.candidates?.[0]?.groundingMetadata) {
console.log('Grounding metadata', response.candidates[0].groundingMetadata);
}
}}
/>
</View>
);
}Generate text from multi-modal input
You can pass in different input types to generate text responses. important - React Native does not have native support for Blob and Buffer types which might be used to facilitate different modal inputs. You may have to use third party libraries for this functionality.
/* Detailed source-code truncated for AI context efficiency. */Generate structured output (e.g. JSON)
The Firebase AI Logic SDK returns responses as unstructured text by default. However, some use cases require structured text, like JSON. For example, you might be using the response for other downstream tasks that require an established data schema.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="generate structured output"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const jsonSchema = Schema.object({
properties: {
characters: Schema.array({
items: Schema.object({
properties: {
name: Schema.string(),
accessory: Schema.string(),
age: Schema.number(),
species: Schema.string(),
},
optionalProperties: ['accessory'],
}),
}),
},
});
const model = getGenerativeModel(ai, {
model: 'gemini-3.1-flash-lite',
generationConfig: {
responseMimeType: 'application/json',
responseSchema: jsonSchema,
},
});
let prompt = "For use in a children's card game, generate 10 animal-based characters.";
let result = await model.generateContent(prompt);
console.log(result.response.text());
}}
/>
</View>
);
}Multi-turn conversations
You can build freeform conversations across multiple turns. The Firebase AI Logic SDK simplifies the process by managing the state of the conversation, so unlike with generateContentStream() or generateContent(), you don't have to store the conversation history yourself.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="start chat session"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, { model: 'gemini-3.1-flash-lite' });
const chat = model.startChat({
history: [
{
role: 'user',
parts: [{ text: 'Hello, I have 2 dogs in my house.' }],
},
{
role: 'model',
parts: [{ text: 'Great to meet you. What would you like to know?' }],
},
],
generationConfig: {
maxOutputTokens: 100,
},
});
const msg = 'How many paws are in my house?';
const result = await chat.sendMessageStream(msg);
let text = '';
for await (const chunk of result.stream) {
const chunkText = chunk.text();
text += chunkText;
}
console.log(text);
// When you want to see the history of the chat
const history = await chat.getHistory();
console.log(history);
}}
/>
</View>
);
}Function calling
Generative models are powerful at solving many types of problems. However, they are constrained by limitations like:
- They are frozen after training, leading to stale knowledge.
- They can't query or modify external data.
Function calling can help you overcome some of these limitations. Function calling is sometimes referred to as tool use because it allows a model to use external tools such as APIs and functions to generate its final response.
/* Detailed source-code truncated for AI context efficiency. */Count tokens
Generative AI models break down data into units called tokens for processing. Each Gemini model has a maximum number of tokens that it can handle in a prompt and response.
The below shows you how to get an estimate of token count for a request. Use totalTokens — totalBillableCharacters was removed in Firebase JS SDK 13 / React Native Firebase v27.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="count tokens"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, { model: 'gemini-3.1-flash-lite' });
// Count tokens for text input
const { totalTokens } = await model.countTokens('Write a story about a magic backpack.');
console.log(`Total tokens: ${totalTokens}`);
// Count tokens for multi-modal input
const prompt = "What's in this picture?";
const imageAsBase64 = '...base64 string image';
const imagePart = {
type: 'inlineData',
inlineData: { mimeType: 'image/jpeg', data: imageAsBase64 },
};
const { totalTokens: multimodalTokens } = await model.countTokens([prompt, imagePart]);
console.log(`Total tokens: ${multimodalTokens}`);
}}
/>
</View>
);
}Generate images with Gemini models
Some Gemini models can return generated images in addition to text. Configure generationConfig.responseModalities and generationConfig.imageConfig on getGenerativeModel() to control output format, aspect ratio, and size.
See the Firebase AI Logic image generation guide for supported models and limits.
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import {
getAI,
getGenerativeModel,
ImageConfigAspectRatio,
ImageConfigImageSize,
ResponseModality,
} from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="generate image with Gemini"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, {
model: 'gemini-3.1-flash-image',
generationConfig: {
responseModalities: [ResponseModality.IMAGE],
imageConfig: {
aspectRatio: ImageConfigAspectRatio.LANDSCAPE_16x9,
imageSize: ImageConfigImageSize.SIZE_1K,
},
},
});
const result = await model.generateContent('Draw a red bicycle on a beach at sunset');
const parts = result.response.candidates?.[0]?.content?.parts ?? [];
const imagePart = parts.find(part => part.inlineData?.mimeType?.startsWith('image/'));
console.log('Generated image mime type', imagePart?.inlineData?.mimeType);
}}
/>
</View>
);
}Ground responses with Google Maps
You can give Gemini access to Google Maps grounding by adding a googleMaps tool. Pass toolConfig.retrievalConfig with the user's location and language so responses can incorporate location-aware information.
When using Grounding with Google Maps you must comply with the Gemini API terms for your API provider.
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="ask with Google Maps grounding"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, {
model: 'gemini-3.1-flash-lite',
tools: [{ googleMaps: {} }],
toolConfig: {
retrievalConfig: {
latLng: { latitude: 37.7749, longitude: -122.4194 },
languageCode: 'en-US',
},
},
});
const result = await model.generateContent(
'What are some highly rated coffee shops within walking distance?',
);
console.log(result.response.text());
console.log(result.response.candidates?.[0]?.groundingMetadata);
}}
/>
</View>
);
}Retrieval config for tools
toolConfig.retrievalConfig applies to all tools on a request. Use it to pass the user's latLng and languageCode when tools need geographic or locale context (for example Google Maps grounding or retrieval-backed tools).
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="generate with retrieval config"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const model = getGenerativeModel(ai, {
model: 'gemini-3.1-flash-lite',
tools: [{ googleSearch: {} }],
toolConfig: {
retrievalConfig: {
latLng: { latitude: 51.5074, longitude: -0.1278 },
languageCode: 'en-GB',
},
},
});
const result = await model.generateContent(
'What events are happening nearby this weekend?',
);
console.log(result.response.text());
}}
/>
</View>
);
}Live sessions
The Live API enables low-latency, bidirectional interaction with Gemini over a persistent connection. Use getLiveGenerativeModel() and connect() to obtain a LiveSession, then send and receive messages in real time.
Browser-only helpers such as startAudioConversation() and AudioConversationController are not available in React Native. Use sendTextRealtime(), sendAudioRealtime(), and sendVideoRealtime() on LiveSession instead.
See the Firebase Live API documentation for model availability and audio format requirements.
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getLiveGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="start live session"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const liveModel = getLiveGenerativeModel(ai, {
model: 'gemini-2.5-flash-native-audio-preview-12-2025',
});
const session = await liveModel.connect();
(async () => {
for await (const message of session.receive()) {
if (message.type === 'serverContent' && message.modelTurn) {
const text = message.modelTurn.parts?.map(part => part.text).join('');
if (text) {
console.log('Model:', text);
}
} else if (message.type === 'toolCall') {
console.log('Tool call', message.functionCalls);
} else if (message.type === 'goingAwayNotice') {
console.log('Connection closing in', message.timeLeft, 'seconds');
}
}
})();
await session.sendTextRealtime('Hello! Can you hear me?');
await session.close();
}}
/>
</View>
);
}Context window compression (Live API)
Long-running Live sessions can exceed the model context window. Set generationConfig.contextWindowCompression on getLiveGenerativeModel() to enable server-side sliding-window compression when token usage crosses a threshold.
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getLiveGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="live session with context compression"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const liveModel = getLiveGenerativeModel(ai, {
model: 'gemini-2.5-flash-native-audio-preview-12-2025',
generationConfig: {
contextWindowCompression: {
triggerTokens: 100000,
slidingWindow: { targetTokens: 80000 },
},
},
});
const session = await liveModel.connect();
await session.send('Start a long conversation...');
await session.close();
}}
/>
</View>
);
}Session resumption (Live API)
Live sessions can be resumed after a disconnect. Pass a SessionResumptionConfig to connect() (use {} to opt in to resumption updates). The server sends sessionResumptionUpdate messages on LiveSession.receive() with a handle you can pass to a later connect() call or to LiveSession.resumeSession().
resumeSession() requires that the original session was opened with session resumption enabled.
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getLiveGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="resume live session"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const liveModel = getLiveGenerativeModel(ai, {
model: 'gemini-2.5-flash-native-audio-preview-12-2025',
});
let resumptionHandle;
const session = await liveModel.connect({});
(async () => {
for await (const message of session.receive()) {
if (message.type === 'sessionResumptionUpdate' && message.resumable) {
resumptionHandle = message.newHandle;
}
}
})();
await session.send('Start a conversation we can resume later.');
// After a disconnect or `goingAwayNotice`, reconnect with the saved handle:
if (resumptionHandle) {
await session.resumeSession({ handle: resumptionHandle });
await session.send('Pick up where we left off.');
}
await session.close();
}}
/>
</View>
);
}Alternatively, call resumeSession({ handle }) on an open session after a goingAwayNotice without closing first:
await session.resumeSession({ handle: resumptionHandle });
await session.connectionPromise;Template models and retrieval config
TemplateGenerativeModel executes server-side prompt templates. Pass a TemplateRequest with templateId, templateVariables, and an optional toolConfig (for example retrievalConfig) to generateContent() or generateContentStream(). For multi-turn chats, pass the same fields via startChat().
import React from 'react';
import { Button, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAI, getTemplateGenerativeModel } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="run template with retrieval config"
onPress={async () => {
const app = getApp();
const ai = getAI(app);
const templateModel = getTemplateGenerativeModel(ai);
const result = await templateModel.generateContent({
templateId: 'weather-assistant-template',
templateVariables: { city: 'Boston' },
toolConfig: {
retrievalConfig: {
latLng: { latitude: 42.3601, longitude: -71.0589 },
languageCode: 'en-US',
},
},
});
console.log(result.response.text());
}}
/>
</View>
);
}Getting ready for production
For mobile and web apps, you need to protect the Gemini API and your project resources (like tuned models) from abuse by unauthorized clients. You can use Firebase App Check to verify that all API calls are from your actual app. See Firebase docs for further information.
- Ensure you have setup App Check for React Native Firebase
- Pass in an instance of App Check to Firebase AI Logic which, under the hood, will call
appCheck.getToken()and use it as part of Firebase AI Logic API requests to the server.
import React from 'react';
import { AppRegistry, Button, Text, View } from 'react-native';
import { getApp } from '@react-native-firebase/app';
import { getAuth } from '@react-native-firebase/auth';
import { initializeAppCheck } from '@react-native-firebase/app-check';
import { getAI, getGenerativeModel, GoogleAIBackend } from '@react-native-firebase/ai';
function App() {
return (
<View>
<Button
title="use App Check and pass into getAI()"
onPress={async () => {
const app = getApp();
const authInstance = getAuth(app);
const appCheckInstance = await initializeAppCheck(app, {
// Configure App Check as per docs...
});
const options = {
appCheck: appCheckInstance,
auth: authInstance,
backend: new GoogleAIBackend(),
};
const ai = getAI(app, options);
const model = getGenerativeModel(ai, { model: 'gemini-3.1-flash-lite' });
const result = await model.generateContent('What is 2 + 2?');
console.log('result', result.response.text());
}}
/>
</View>
);
}Analytics Usage Index (`docs/analytics/usage/index.mdx`)
title: Analytics next: /analytics/screen-tracking previous: /ai/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the analytics module
yarn add @react-native-firebase/analytics
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: On-device conversion measurement helpers (initiateOnDeviceConversionMeasurement*) are iOS only; on Android and web the JS layer resolves without calling native (no-op). logTransaction (verified iOS in-app purchase events) is iOS only and rejects on other platforms. Analytics supports only the default Firebase app.
What does it do
Analytics collects usage and behavior data for your app. Its two primary concerns are:
- Events: What is happening in your app, such as user actions, system events, or errors.
- User properties: Attributes you define to describe segments of your user base, such as language preference or geographic location.
Analytics automatically logs some events and user properties; you don't need to add any code to enable them. However, Analytics also allows you to log custom or predefined events within your app. How you can do this will be explained below.
Usage
Analytics offers a wealth of Predefined Events to track user behavior. Analytics also offers folks the ability to log Custom Events . If you're already familiar with Google Analytics, this method is equivalent to using the event command in gtag.js.
Event Parameters
Please pay very special attention to what parameters you send in for any events - custom, predefined or otherwise.
WARNING
Parameters are not validated and incorrect parameters will silently be accepted but then fail to log an event in the Analytics console.
It is the developer's responsibility to verify that their parameters are correct and are being logged correctly.
Different event types require different parameters (some require no parameters, some require an array of strings, most require just a string, etc). The developer must examine the reference for each type of event and send the correct parameters. You may watch device logs and the Analytics console to make sure the events are correctly sent to Google Analytics.
Custom Events
Below is an example showing how a custom event can be logged. Please be aware that primitive data types or arrays of primitive data types are logged in your Firebase Analytics console.
import react, { useEffect } from 'react';
import { View, Button } from 'react-native';
import { getAnalytics, logEvent } from '@react-native-firebase/analytics';
function App() {
return (
<View>
<Button
title="Add To Basket"
onPress={async () =>
await logEvent(getAnalytics(), 'basket', {
id: 3745092,
item: 'mens grey t-shirt',
description: ['round neck', 'long sleeved'],
size: 'L',
})
}
/>
</View>
);
}Predefined Events
To help you get started, Analytics provides a number of event methods that are common among
different types of apps, including retail and e-commerce, travel, and gaming apps. To learn more about these events and
when to use them, browse the Events and properties
articles in the Firebase Help Center.
Below is a sample of how to use one of the predefined methods the Analytics module provides for you:
import react, { useEffect } from 'react';
import { View, Button } from 'react-native';
import { getAnalytics, logSelectContent } from '@react-native-firebase/analytics';
function App() {
return (
<View>
<Button
title="Press me"
// Logs in the firebase analytics console as "select_content" event
// only accepts the two object properties which accept strings.
onPress={async () =>
await logSelectContent(getAnalytics(), {
content_type: 'clothing',
item_id: 'abcd',
})
}
/>
</View>
);
}For a full reference to predefined events and expected parameters, please check out the reference API.
Reserved Events
The Analytics package works out of the box, however a number of events are automatically reported to Firebase.
These event names are called as 'Reserved Events'. Attempting to send any custom event using the logEvent method
with any of the following event names will throw an error.
| Reserved Events Names | ||
|---|---|---|
ad_activeview |
ad_click |
ad_exposure |
ad_impression |
ad_query |
ad_reward |
adunit_exposure |
app_background |
app_clear_data |
app_remove |
app_store_refund |
app_store_subscription_cancel |
app_store_subscription_convert |
app_store_subscription_renew |
app_update |
app_upgrade |
error |
first_open |
first_visit |
in_app_purchase |
notification_dismiss |
notification_foreground |
notification_open |
notification_receive |
os_update |
session_start |
session_start_with_rollout |
user_engagement |
App instance id
Below is an example showing how to retrieve the app instance id of the application. This will return null on android
if FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE has been set to FirebaseAnalytics.ConsentStatus.DENIED and null on
iOS if ConsentType.analyticsStorage has been set to ConsentStatus.denied.
import { getAnalytics, getAppInstanceId } from '@react-native-firebase/analytics';
// ...
const appInstanceId = await getAppInstanceId(getAnalytics());Web / Other platform instance id
Ensure you have installed an Async Storage provider for Firebase to preserve the instance id. Failure to do so means the instance id will be reset every time the application terminates.
The main documentation for "other platform" support contains an example.
Disable Ad Id usage on iOS
Apple has a strict ban on the usage of Ad Ids ("IDFA") in Kids Category apps. They will not accept any app
in the Kids category if the app accesses the IDFA iOS symbols.
Additionally, apps must implement Apples "App Tracking Transparency" (or "ATT") requirements if they access IDFA symbols.
However, if an app does not use IDFA and otherwise handles data in an ATT-compatible way, it eliminates this ATT requirement.
If you need to avoid IDFA usage while still using analytics, then you need firebase-ios-sdk v7.11.0 or greater and to define the following variable in your Podfile:
$RNFirebaseAnalyticsWithoutAdIdSupport = trueDuring pod install, using that variable installs the FirebaseAnalytics/Core Pod but not the FirebaseAnalytics/IdentitySupport Pod, so you may use Firebase Analytics in Kids Category apps,
or Firebase Analytics without needing the App Tracking Transparency handling (assuming no other parts
of your app handle data in a way that requires ATT)
Note that for obvious reasons, configuring Firebase Analytics for use without IDFA is incompatible with AdMob
Google Analytics on-device conversion measurement
If you would like to enable Google Analytics on-device conversion measurement APIs on iOS, define the following variable in your Podfile:
$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = trueDuring pod install, using that variable adds the GoogleAdsOnDeviceConversion Pod.
If you use Expo, including EAS Build, add the Analytics config plugin to your app.json / app.config.js instead of editing the generated Podfile manually:
[
"@react-native-firebase/analytics",
{
"ios": {
"googleAppMeasurementOnDeviceConversion": true
}
}
]This adds $RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true to the generated iOS Podfile during prebuild.
Device Identification
If you would like to enable Firebase Analytics to generate automatic audience metrics for iOS (as it does by default in Android), you must link additional iOS libraries, as documented by the Google Firebase team. Specifically you need to link in AdSupport.framework.
The way to do this using CocoaPods is to add this variable to your Podfile so @react-native-firebase/analytics will link it in for you:
$RNFirebaseAnalyticsEnableAdSupport = trueNote: this setting will have no effect if you disabled Ad IDs as described above, since this setting is specifically linking in the AdSupport framework which requires the Ad IDs.
firebase.json
Disable Auto-Initialization
Analytics can be further configured to disable auto collection of Analytics data. This is useful for opt-in-first
data flows, for example when dealing with GDPR compliance. This is possible by setting the below noted property
on the firebase.json file at the root of your project directory.
// <project-root>/firebase.json
{
"react-native": {
"analytics_auto_collection_enabled": false
}
}To re-enable analytics (e.g. once you have the users consent), call the setAnalyticsCollectionEnabled method:
import { getAnalytics, setAnalyticsCollectionEnabled } from '@react-native-firebase/analytics';
// ...
await setAnalyticsCollectionEnabled(getAnalytics(), true);To update user's consent (e.g. once you have the users consent), call the setConsent method:
import { getAnalytics, setConsent } from '@react-native-firebase/analytics';
// ...
await setConsent(getAnalytics(), {
analytics_storage: true,
ad_storage: true,
ad_user_data: true,
ad_personalization: true,
});Disable screenview tracking
Analytics automatically tracks some information about screens in your application, such as the class name of the UIViewController or Activity that is currently in focus.
Automatic screenview reporting can be turned off/on through google_analytics_automatic_screen_reporting_enabled property of firebase.json file.
// <project-root>/firebase.json
{
"react-native": {
"google_analytics_automatic_screen_reporting_enabled": false
}
}Seeing Events in Firebase Console Realtime View or Analytics DebugView
Events show in the Firebase Console Realtime View within a few seconds of your app sending the events. This is an easy way to verify your events implementation as you develop your application.
However, the Realtime View on Firebase Console offers no way to filter to a specific stream of events so after your app launches your development events will be mixed with all events from your app.
To examine just your development events you will need to use the Analytics DebugView available on the main Google Analytics site for your app as documented in the "Monitor the events in DebugView" section of the Google Analytics documentation
Analytics events only show up in DebugView if marked correctly. Follow the instructions below for each platform to mark your events as Debug events.
iOS
When running on iOS in debug, events won't be logged by default. If you want to see events in DebugView in the Firebase Console when running debug builds, you'll need to first set a flag when launching in debug. This flag used to be variously called -FIRAnalyticsDebugEnabled and -FIRDebugEnabled, but please check the previous link.
To always set the flag when running debug builds of your app, you can edit your scheme in Xcode to always include the flag.
Android
When running on Android in debug, events won't be logged by default. If you want to see events in DebugView in the Firebase Console when running debug builds, you'll need to run the following command on the terminal adb shell setprop debug.firebase.analytics.app - where `` should be replaced with your app's package name.
Other / Web
To mark your events as "Debug" events for platforms using react-native-firebase "other" platform support, you need to set the global debug flag globalThis.RNFBDebug to true then reload the app.
This toggle must be set to the value you want before accessing the analytics instance for the first time, so you should do it as early in your app's bootstrap sequence as possible.
For example, you might modify your index.js file like so:
/**
* @format
*/
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
// \/ Add these lines below
// Enable debug mode for react-native-firebase:
if (__DEV__) globalThis.RNFBDebug = true;
// /\ Add these lines above
AppRegistry.registerComponent(appName, () => App);App Check Usage Index (`docs/app-check/usage/index.mdx`)
title: App Check next: /app-distribution/usage previous: /analytics/screen-tracking
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app"
module, view the Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the app-check module
yarn add @react-native-firebase/app-check
# If you're developing your app using iOS, run this command
cd ios/ && pod installApp Check requires you set the minimum iOS Deployment version in ios/Podfile to 11.0 or greater.
You may have Xcode compiler errors after including the App Check module, specifically referencing linker problems and missing directories.
You may find excluding the i386 architecture via an addition to the ios/Podfile post_install hook like the below works:
installer.aggregate_targets.each do |aggregate_target|
aggregate_target.user_project.native_targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
config.build_settings['EXCLUDED_ARCHS'] = 'i386'
end
end
aggregate_target.user_project.save
endPlatform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: Use ReactNativeFirebaseAppCheckProvider for native attestation (Device Check, App Attest, Play Integrity). firebase-js-sdk ReCaptchaEnterpriseProvider and ReCaptchaV3Provider are web only.
What does it do
App Check works alongside other Firebase services to help protect your backend resources from abuse, such as billing fraud or phishing. With App Check, devices running your app will use an app or device attestation provider that attests to one or both of the following:
- Requests originate from your authentic app
- Requests originate from an authentic, untampered device
This attestation is attached to every request your app makes to your Firebase backend resources.
This App Check module has built-in support for using the following services as attestation providers:
- DeviceCheck on iOS
- App Attest on iOS
- Play Integrity on Android (requires distribution from Play Store to successfully fetch tokens)
- SafetyNet on Android (deprecated)
- Debug providers on both platforms
App Check currently works with the following Firebase products:
- Realtime Database
- Cloud Firestore
- Cloud Storage
- Cloud Functions (callable functions)
The official Firebase App Check documentation has more information, including about the iOS AppAttest provider, and testing/ CI integration, it is worth a read.
Usage
Register Firebase Apps
Before the App Check package can be used on iOS or Android, the corresponding App must be registered in the firebase console.
For instructions on how to generate required keys and register an app for the desired attestation provider, follow Step 1 in these firebase guides:
- Get started using App Check with DeviceCheck on Apple platforms
- Get started using App Check with App Attest on Apple platforms
- Get started using App Check with Play Integrity on Android
- Get started using App Check with SafetyNet on Android (deprecated)
Additionally, You can reference the iOS private key creation and registrations steps outlined in the Cloud Messaging iOS Setup.
Initialize
If you're using Expo Managed Workflow, you can load the
@react-native-firebase/app-checkconfig plugin to skip the native setup step below. The plugin only registers the native module beforeFirebaseApp.configure()(Firebase requires this order regardless of which provider you use); you still need to callinitializeAppCheckfrom JavaScript.
You must call initializeAppCheck prior to calling any Firebase backend services for App Check to function. Until initializeAppCheck (or the deprecated activate) configures a provider, App Check is pending: any getToken / getLimitedUseToken call fails immediately with appCheck/provider-not-ready instead of fetching a real token.
All react-native >= 0.77 with AppDelegate.swift
The AppCheck pod does not expose a Swift-importable module surface (its C++ codegen headers stay private), so importing it directly in a Swift file does not work.
Edit the bridging header at <your project name>/ios/<your project-name>-Bridging-Header.h
You will need to add the line indicated in the example below:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
+ #import "RNFBAppCheckModule.h" // <-- new for AppCheck to workAfter doing that, follow the instructions below to add AppCheck initialization to your AppDelegate.swift file depending on the react-native version you use.
Configure AppCheck with iOS credentials (react-native 0.79+)
To do that, edit your ios/ProjectName/AppDelegate.swift and add the following two lines:
At the top of the file, import the FirebaseCore SDK right after import UIKit:
And within your existing didFinishLaunchingWithOptions method, add the following to the top of the method:
import UIKit
+ import FirebaseCore // <-- From App/Core integration, no other Firebase items needed
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
...
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
+ RNFBAppCheckModule.sharedInstance() // <-- new for AppCheck to work
+ FirebaseApp.configure() // <-- From App/Core integrationConfigure AppCheck with iOS credentials (react-native >= 0.77 && < 0.79)
To do that, edit your ios/ProjectName/AppDelegate.swift and add the following two lines:
At the top of the file, import the FirebaseCore SDK right after import UIKit:
And within your existing didFinishLaunchingWithOptions method, add the following to the top of the method:
import UIKit
+ import FirebaseCore // <-- From App/Core integration, no other Firebase items needed
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
@main
class AppDelegate: RCTAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
+ RNFBAppCheckModule.sharedInstance() // <-- new for AppCheck to work
+ FirebaseApp.configure() // <-- From App/Core integrationNote: Do not add
import RNFBAppCheckin Swift. The AppCheck pod is Obj-C only and does not produce a Swift module. Use the bridging header import above instead.
Configure Firebase with iOS credentials (react-native < 0.77)
To do that, edit your ios/ProjectName/AppDelegate.mm and add the following two lines:
#import "AppDelegate.h"
#import "RNFBAppCheckModule.h" // ⬅️ ADD THIS LINE
#import <Firebase.h>
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Initialize RNFBAppCheckModule, it sets the custom RNFBAppCheckProviderFactory
// which lets us configure any of the available native platform providers,
// and reconfigure if needed, dynamically after `[FIRApp configure]` just like the other platforms.
[RNFBAppCheckModule sharedInstance]; // ⬅️ ADD THIS LINE BEFORE [FIRApp configure]
[FIRApp configure];
...
}There are several differences between the web, Apple, and Android platform SDKs produced by Firebase, which react-native-firebase smooths over to give you a common, firebase-js-sdk compatible API.
How do we do this? We use the standard firebase-js-sdk v9 API initializeAppCheck, and take advantage of its parameters which allow the use of an AppCheckOptions argument that itself allows a CustomProvider.
It is through the use of a react-native-specific ReactNativeFirebaseAppCheckProvider that we can offer runtime configuration capability at the javascript level, including the ability to switch providers dynamically.
So AppCheck module initialization is done in two steps in react-native-firebase - first you create and configure the custom provider, then you initialize AppCheck using that custom provider.
Starting in v25, the modular App Check helpers and types are exported from @react-native-firebase/app-check at the package root to better match the Firebase JS SDK. For example, import initializeAppCheck, AppCheck, and AppCheckTokenResult directly from @react-native-firebase/app-check when using the modular API.
Configure a Custom Provider
To configure the react-native-firebase custom provider, first obtain one, then configure it according to the providers you want to use on each platform.
import { ReactNativeFirebaseAppCheckProvider } from '@react-native-firebase/app-check';
const rnfbProvider = new ReactNativeFirebaseAppCheckProvider();
rnfbProvider.configure({
android: {
provider: __DEV__ ? 'debug' : 'playIntegrity',
debugToken: 'some token you have configured for your project firebase web console',
},
apple: {
provider: __DEV__ ? 'debug' : 'appAttestWithDeviceCheckFallback',
debugToken: 'some token you have configured for your project firebase web console',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'unknown',
},
});Install the Custom Provider
Once you have the custom provider configured, install it in app-check using the firebase-js-sdk compatible API, while saving the returned instance for usage:
import { getApp } from '@react-native-firebase/app';
import { initializeAppCheck } from '@react-native-firebase/app-check';
const appCheck = await initializeAppCheck(getApp(), {
provider: rnfbProvider,
isTokenAutoRefreshEnabled: true,
});Inline Provider Configuration
If you do not need to keep a provider instance around, you can pass the React Native provider configuration inline using providerOptions:
import { getApp } from '@react-native-firebase/app';
import { initializeAppCheck } from '@react-native-firebase/app-check';
const appCheck = await initializeAppCheck(getApp(), {
provider: {
providerOptions: {
android: {
provider: __DEV__ ? 'debug' : 'playIntegrity',
debugToken: 'some token you have configured for your project firebase web console',
},
apple: {
provider: __DEV__ ? 'debug' : 'appAttestWithDeviceCheckFallback',
debugToken: 'some token you have configured for your project firebase web console',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'unknown',
},
},
},
isTokenAutoRefreshEnabled: true,
});Verify AppCheck was initialized correctly
After initializing the custom provider, you can verify AppCheck is working by logging a response from the token server:
import { getToken } from '@react-native-firebase/app-check';
try {
// `appCheckInstance` is the saved return value from initializeAppCheck
const { token } = await appCheckInstance.getToken(true);
if (token.length > 0) {
console.log('AppCheck verification passed');
}
} catch (error) {
console.log('AppCheck verification failed');
}Listening for token changes
On Android, you can subscribe to App Check token updates with onTokenChanged. On iOS this listener is not implemented yet – subscribing will no-op and log a warning. If you need to react to token changes on iOS, prefer polling getToken on demand or rely on automatic refresh.
import { onTokenChanged, getToken } from '@react-native-firebase/app-check';
// Android: receives updates. iOS: no-op (native API does not exist on the SDK).
const unsubscribe = onTokenChanged(appCheckInstance, async ({ token }) => {
console.log('App Check token updated:', token);
});
// iOS-friendly approach: request a fresh token when needed
const { token } = await appCheckInstance.getToken(true);Automatic Data Collection
App Check has an "tokenAutoRefreshEnabled" setting. This may cause App Check to attempt a remote App Check token fetch prior to user consent. In certain scenarios, like those that exist in GDPR-compliant apps running for the first time, this may be unwanted.
You may configure this setting in firebase.json such that your desired configuration is in place even before you the react-native javascript bundle begins executing and allows for runtime configuration.
If unset, the "tokenAutoRefreshEnabled" setting will defer to the app's "automatic data collection" setting, which may be set in firebase.json, or if you wish directly in the Info.plist or AndroidManifest.xml according to the Firebase native SDK documentation. Unless otherwise configured, it will default to true implying there will be automatic data collection and app check token refresh attempts.
Using App Check tokens for non-firebase services
The official documentation shows how to use getToken to access the current App Check token and then verify it in external services.
Troubleshooting
`appCheck/provider-not-ready`
If getToken / getLimitedUseToken rejects with appCheck/provider-not-ready, App Check has not been configured yet for that app. Call initializeAppCheck (or the deprecated activate) before requesting tokens or calling any App Check-protected Firebase service.
This error replaces an older iOS behavior where App Check could install the debug provider before initializeAppCheck ran, including in release builds. That could exchange a debug token with Firebase's backend outside of development, showing up as unexplained exchangeDebugToken 403/429 responses in your logs. If you saw those errors before upgrading, look for a code path that requests a token before initializeAppCheck completes and move it after.
Manually Setting Up App Check Debug Token for Testing Environments / CI
on iOS
The react-native-firebase CustomProvider implementation allows for runtime configuration of the debug provider as well as a debugToken in the ios CustomProvider options. This allows the easy use of a token pre-configured in the Firebase console, allowing for dynamic configuration and testing of AppCheck in CI environments or iOS Simulators.
on Android
The react-native-firebase CustomProvider implementation allows for runtime configuration of the debug provider as well as a debugToken in the android CustomProvider options. This allows the easy use of a token pre-configured in the Firebase console, allowing for dynamic configuration and testing of AppCheck in CI environments or Android Emulators.
There are a variety of other ways to obtain and configure debug tokens for AppCheck testing, a few of which follow:
A) When testing on an actual android device (debug build)
Start your application on the android device.
Use
$adb logcat | grep DebugAppCheckProviderto grab your temporary secret from the android logs. The output should look lit this:textD DebugAppCheckProvider: Enter this debug secret into the allow list in the Firebase Console for your project: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXIn the Project Settings > App Check section of the Firebase console, choose Manage debug tokens from your app's overflow menu. Then, register the debug token you logged in the previous step.
B) Specifying a generated `FIREBASE_APP_CHECK_DEBUG_TOKEN` -- building for CI/CD (debug build)
When you want to test using an Android virtual device -or- when you prefer to (re)use a token of your choice -- e.g. when configuring a CI/CD pipeline -- use the following steps:
In the Project Settings > App Check section of the Firebase console, choose Manage debug tokens from your app's overflow menu. Then, register a new debug token by clicking the Add debug token button, then Generate token.
Pass the token you created in the previous step by supplying a
FIREBASE_APP_CHECK_DEBUG_TOKENenvironment variable to the process that build your react-native android app. e.g.:textFIREBASE_APP_CHECK_DEBUG_TOKEN="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" react-native run-android
Please note that once the android app has successfully passed the app-checks controls on the device, it will keep passing them, whether you rebuild without the secret token or not. To completely reset app-check, you must first uninstall, and then re-build / install.
C) When using Expo Development Client
When using expo-dev-client, the process is a little different, especially on an android emulator.
- In the Project Settings > App Check section of the Firebase console, choose Manage debug tokens from your app's overflow menu. Then, register a new debug token by clicking the Add debug token button, then Generate token.
- Pass the token you created in the previous step by supplying a
FIREBASE_APP_CHECK_DEBUG_TOKENenvironment variable in your eas.json development profile:
{
...
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"env": {
...
"FIREBASE_APP_CHECK_DEBUG_TOKEN": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
},
...
},
...
}Rebuild your development client:
texteas build --profile development --platform android
App Distribution Usage Index (`docs/app-distribution/usage/index.mdx`)
title: App Distribution next: /auth/usage previous: /app-check/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app"
module, view the Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the app-distribution module
yarn add @react-native-firebase/app-distribution
# If you're developing your app using iOS, run this command
cd ios/ && pod installAdd the App Distribution Plugin
If you're using Expo, make sure to add the
@react-native-firebase/app-distributionconfig plugin to yourapp.jsonorapp.config.js. It handles the below installation steps for you. For instructions on how to do that, view the Expo installation section.
On Android, you need to install the Google App Distribution Plugin.
Add the plugin to your /android/build.gradle file as a dependency:
buildscript {
dependencies {
// ...
classpath 'com.google.firebase:firebase-appdistribution-gradle:5.3.0'
}Apply the plugin via the /android/app/build.gradle file (at the top):
apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.appdistribution'Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
React Native only: There is no firebase-js-sdk web equivalent for App Distribution.
What does it do
Firebase App Distribution gives a holistic view of your beta testing program across iOS and Android, providing you with valuable feedback before a new release is in production. You can send pre-release versions of your app using the console or your CI servers, and installing your app is easy for testers.
Firebase App Distribution makes distributing your apps to trusted testers painless. By getting your apps onto testers' devices quickly, you can get feedback early and often. And if you use Crashlytics in your apps, you’ll automatically get stability metrics for all your builds, so you know when you’re ready to ship.
Key capabilities
- Cross-platform Manage both your iOS and Android pre-release distributions from the same place.
- Fast distributions Get early releases into your testers' hands quickly, with fast onboarding, no SDK to install, and instant app delivery.
- Fits into your workflow Distribute builds using the Firebase console, the Firebase Command Line Interface (CLI) tool, - or Gradle (Android). Automate distribution by integrating the CLI into CI jobs.
- Tester management Manage your testing teams by organizing them into groups. Easily add new testers with email invitations that walk them through the onboarding process. See the status of each tester for specific versions of your app: view who has accepted a testing invitation and downloaded the app.
- Works with Android App Bundles Distribute releases to testers for your Android App Bundle in Google Play. App - Distribution integrates with Google Play's internal app sharing service to streamline your app testing and launching processes.
- Works with Crashlytics When combined with Crashlytics, get insights into the stability of your test distributions.
The official Firebase App Check documentation has more information, including about build upload integration, it is worth a read.
Usage
The react-native-firebase module for App Distribution is meant to expose the new version alert capabilities of the iOS SDK. The majority of the App Distribution Firebase service depends on native build/release integrations. Those build/release integrations must be natively implemented for iOS and Android, according to the upstream docs from Firebase or our build system provider.
New Version Alerts
On iOS if you include the App Distribution module, you can optionally enable in-app alerts that appear when new builds are available to test.
Tester Sign-in Status
The methods signInTester and isTesterSignedIn give you more flexibility customizing your tester's sign-in experience, so it can better match your app's look and feel.
You may check if your tester has already signed into their Firebase App Distribution tester account, so you can choose to display your sign-in UI only for testers who haven't yet signed in. After the tester has signed in, you can then call checkForUpdate to check whether the tester has access to a new build.
Auth Usage Index (`docs/auth/usage/index.mdx`)
title: Authentication next: /auth/social-auth previous: /app-distribution/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app"
module, view the Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the authentication module
yarn add @react-native-firebase/auth
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: Several firebase-js-sdk web helpers throw on React Native (setPersistence, getRedirectResult, revokeAccessToken, useDeviceLanguage, linkWithPhoneNumber, reauthenticateWithPhoneNumber). useUserAccessGroup is iOS only. See Migrating to v26 — Platform behavior differences.
What does it do
Firebase Authentication provides backend services & easy-to-use SDKs to authenticate users to your app. It supports
authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more.
Firebase Authentication integrates tightly with other Firebase services, and it leverages industry standards like OAuth
2.0 and OpenID Connect, so it can be easily integrated with your custom backend.
Usage
Listening to authentication state
In most scenarios using Authentication, you will want to know whether your users are currently signed-in or signed-out
of your application. The module provides a method called onAuthStateChanged which allows you to subscribe to the users
current authentication state, and receive an event whenever that state changes.
It is important to remember the onAuthStateChanged listener is asynchronous and will trigger an initial state once
a connection with Firebase has been established. Therefore it is important to setup an "initializing" state which blocks
render of our main application whilst the connection is established:
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import { getAuth, onAuthStateChanged } from '@react-native-firebase/auth';
function App() {
// Set an initializing state whilst Firebase connects
const [initializing, setInitializing] = useState(true);
const [user, setUser] = useState();
// Handle user state changes
function handleAuthStateChanged(user) {
setUser(user);
if (initializing) setInitializing(false);
}
useEffect(() => {
const subscriber = onAuthStateChanged(getAuth(), handleAuthStateChanged);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing) return null;
if (!user) {
return (
<View>
<Text>Login</Text>
</View>
);
}
return (
<View>
<Text>Welcome {user.email}</Text>
</View>
);
}If the user returned within the handler is null we assume the user is currently signed-out, otherwise they are
signed-in and a User interface is returned.
The onAuthStateChanged method also returns an unsubscriber function which allows us to stop listening for events whenever
the hook is no longer in use.
Persisting authentication state
On web based applications, the Firebase Web SDK takes advantage of features such as cookies and local storage to persist
the users authenticated state across sessions. The native Firebase SDKs also provide this functionality using device native SDKs,
ensuring that a users previous authentication state between app sessions is persisted.
The user is able to clear their state by deleting the apps data/cache from the device settings.
Anonymous sign-in
Some applications don't require authentication, which make it tricky to identify what users are doing throughout your app.
If connecting with external APIs, it is also useful to add an extra layer of security by ensuring the users request is
from the app. This can be achieved with the signInAnonymously method, which creates a new anonymous user which is persisted,
allowing you to integrate with other services such as Analytics by providing a user ID.
Ensure the "Anonymous" sign-in provider is enabled on the Firebase Console.
import { getAuth, signInAnonymously } from '@react-native-firebase/auth';
signInAnonymously(getAuth())
.then(() => {
console.log('User signed in anonymously');
})
.catch(error => {
if (error.code === 'auth/operation-not-allowed') {
console.log('Enable anonymous in your firebase console.');
}
console.error(error);
});Once successfully signed in, any onAuthStateChanged listeners will trigger an event
with the User details.
In case any errors occur, the module provides support for identifying what specifically went wrong by attaching a code
to the error. For a full list of error codes available, view the Firebase documentation.
Email/Password sign-in
Email/password sign in is a common method for user sign in on applications. This requires the user to provide an email
address and secure password. Users can both register and sign in using a method called createUserWithEmailAndPassword
or sign in to an existing account with signInWithEmailAndPassword.
Ensure the "Email/Password" sign-in provider is enabled on the Firebase Console.
The createUserWithEmailAndPassword performs two operations; first creating the user if they do not already exist, and
then signing them in.
import { getAuth, createUserWithEmailAndPassword } from '@react-native-firebase/auth';
createUserWithEmailAndPassword(getAuth(), '[email protected]', 'SuperSecretPassword!')
.then(() => {
console.log('User account created & signed in!');
})
.catch(error => {
if (error.code === 'auth/email-already-in-use') {
console.log('That email address is already in use!');
}
if (error.code === 'auth/invalid-email') {
console.log('That email address is invalid!');
}
console.error(error);
});Once successfully created and/or signed in, any onAuthStateChanged listeners will trigger an event
with the User details.
In case any errors occur, the module provides support for identifying what specifically went wrong by attaching a code
to the error. For a full list of error codes available, view the Firebase documentation.
Authenticate with backend server
The user's token should be used for authentication with your backend systems. The token is fetched with the getIdToken method. As mentioned in the Firebase documentation, the uid should not be used for authentication.
Signing out
If you'd like to sign the user out of their current authentication state, call the signOut method:
import { getAuth, signOut } from '@react-native-firebase/auth';
signOut(getAuth()).then(() => console.log('User signed out!'));Once successfully signed out, any onAuthStateChanged listeners will trigger an event
with the user parameter being a null value.
Additionally, calling revokeAccess() on your Google sign-in library forgets the user on the device (for example GoogleOneTapSignIn.revokeAccess() from react-native-nitro-google-signin, or GoogleSignin.revokeAccess() from @react-native-google-signin/google-signin). The next sign-in will show the account picker again. Without it, the last account may be reused automatically.
Other sign-in methods
Firebase also supports authenticating with external provides. To learn more, view the documentation for your authentication
method:
- Apple Sign-In.
- Facebook Sign-In.
- Twitter Sign-In.
- Google Sign-In.
- Microsoft Sign-In.
- Phone Number Sign-In.
- Email Link Sign-In (passwordless App Links / Universal Links).
Crashlytics Usage Index (`docs/crashlytics/usage/index.mdx`)
title: Crashlytics next: /crashlytics/crash-reports previous: /app/utils
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the Crashlytics module
yarn add @react-native-firebase/crashlytics
# If you're developing your app using iOS, run this command
cd ios/ && pod installOnce installed, you must complete the following additional setup steps for Android:
If you're using Expo, make sure to add the
@react-native-firebase/crashlyticsconfig plugin to yourapp.jsonorapp.config.js. It handles the Android installation steps for you. For instructions on how to do that, view the Expo installation section.
If you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
You may like reading a short article we wrote that explains how to configure and most importantly verify your crashlytics installation so you are sure it is working. https://invertase.io/blog/react-native-firebase-crashlytics-configuration
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
React Native only: There is no firebase-js-sdk web equivalent for Crashlytics.
What does it do
Crashlytics helps you to collect analytics and details about crashes and errors that occur in your app. It does this through three aspects:
- Logs: Log events in your app to be sent with the crash report for context if your app crashes.
- Crash reports: Every crash is automatically turned into a crash report and sent.
- Stack traces: Even when an error is caught and your app recovers, the JavaScript stack trace can still be sent.
To learn more, view the Firebase Crashlytics documentation.
Usage
Use the log method throughout your app to accumulate extra context for possible crashes that can happen. For additional context, Crashlytics also offers various methods to set attributes for the crash report. You can also test Crashlytics by forcing a crash through the crash method.
Crashlytics also supports sending JavaScript stack traces to the Firebase console. This can be used in any situation where an error occurs but is caught by your own code to recover gracefully. To send a stack trace, pass a JavaScript Error to the recordError method.
Crash reporting is disabled by default whilst developing. To enable this, view the enable debug crash logs documentation.
Crash Attributes
There are various methods to set attributes for the crash report, in order to provide analytics for crashes and help you review them. You can use set methods to set predefined attributes, but you can also set your own custom attributes.
import React, { useEffect } from 'react';
import { View, Button } from 'react-native';
import {
getCrashlytics,
log,
setUserId,
setAttribute,
setAttributes,
crash,
} from '@react-native-firebase/crashlytics';
async function onSignIn(user) {
const crashlytics = getCrashlytics();
log(crashlytics, 'User signed in.');
await Promise.all([
setUserId(crashlytics, user.uid),
setAttribute(crashlytics, 'credits', String(user.credits)),
setAttributes(crashlytics, {
role: 'admin',
followers: '13',
email: user.email,
username: user.username,
}),
]);
}
export default function App() {
useEffect(() => {
log(getCrashlytics(), 'App mounted.');
}, []);
return (
<View>
<Button
title="Sign In"
onPress={() =>
onSignIn({
uid: 'Aa0Bb1Cc2Dd3Ee4Ff5Gg6Hh7Ii8Jj9',
username: 'Joaquin Phoenix',
email: '[email protected]',
credits: 42,
})
}
/>
<Button title="Test Crash" onPress={() => crash(getCrashlytics())} />
</View>
);
}Error Reports
Even if you catch unexpected errors, in order for your app to recover and behave smoothly you can still report them through
Crashlytics using the recordError method. This will also provide you with the associated stack trace.
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import { getCrashlytics, log, recordError } from '@react-native-firebase/crashlytics';
const users = [];
export default function App() {
const [userCounts, setUserCounts] = useState(null);
function updateUserCounts() {
const crashlytics = getCrashlytics();
log(crashlytics, 'Updating user count.');
try {
if (users) {
setUserCounts(userCounts.push(users.length));
}
} catch (error) {
recordError(crashlytics, error);
console.log(error);
}
}
useEffect(() => {
log(getCrashlytics(), 'App mounted.');
if (users == true) setUserCounts([]);
updateUserCounts();
}, []);
if (userCounts) {
return (
<View>
<Text>There are currently {userCounts[userCounts.length - 1]} users.</Text>
</View>
);
}
return (
<View>
<Text>Unable to display user information.</Text>
</View>
);
}Opt-out
As Crashlytics will be sending certain information regarding the user, users may want to opt-out of the crash reporting.
This can be done throughout the app with a simple method call to setCrashlyticsCollectionEnabled:
import React, { useState } from 'react';
import { View, Button, Text } from 'react-native';
import {
getCrashlytics,
setCrashlyticsCollectionEnabled,
crash,
} from '@react-native-firebase/crashlytics';
export default function App() {
const [enabled, setEnabled] = useState(getCrashlytics().isCrashlyticsCollectionEnabled);
async function toggleCrashlytics() {
const crashlytics = getCrashlytics();
await setCrashlyticsCollectionEnabled(crashlytics, !enabled);
setEnabled(crashlytics.isCrashlyticsCollectionEnabled);
}
return (
<View>
<Button title="Toggle Crashlytics" onPress={toggleCrashlytics} />
<Button title="Crash" onPress={() => crash(getCrashlytics())} />
<Text>Crashlytics is currently {enabled ? 'enabled' : 'disabled'}</Text>
</View>
);
}firebase.json
Disable Auto Collection
Additionally, you can configure whether Crashlytics sends out any reports through the auto_collection_enabled option in
your firebase.json config. If you want users to opt-in, it is recommended that you disable this here and enable it later
through the method once they opt-in.
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_auto_collection_enabled": false
}
}Enable debug crash logs
Because you have stack traces readily available while you're debugging your app, Crashlytics is disabled by default in debug mode. You can set Crashlytics to be enabled regardless of debug mode through the debug_enabled option in your firebase.json.
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_debug_enabled": true
}
}Crashlytics NDK
React Native Firebase supports Crashlytics NDK reporting
which is enabled by default but will require a change as described in that link to enable symbol upload.
This allows Crashlytics to capture crashes originating from the Yoga layout engine used by React Native.
You can disable Crashlytics NDK in your firebase.json config.
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_ndk_enabled": false
}
}Crashlytics Javascript stacktrace issue generation
React Native Crashlytics module by default installs a global javascript exception handler, and it records a crash with a javascript stack trace any time an unhandled javascript exception is thrown. Sometimes it is not desirable behavior since it might duplicate issues in combination with the default mode of javascript global exception handler chaining. We recommend leaving JS crashes enabled and turning off exception handler chaining. However, if you have special crash handling requirements, you may disable this behavior by setting the appropriate option to false:
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_is_error_generation_on_js_crash_enabled": false
}
}Crashlytics Javascript exception handler chaining
React Native Crashlytics module's global javascript exception handler by default chains to any previously installed global javascript exception handler after logging the crash with the javascript stack trace. In default react-native setups, this means in development you will then see a "red box" and in release mode you will see a second native crash in the Crashlytics console with no javascript stack trace. These duplicate crash reports are probably not desirable, and the one from the chained handler will not have the javascript stack trace. We recommend disabling this once Crashlytics is integrated in testing. It is enabled by default for easier initial integration testing and to be sure introducing the option was not a breaking change. You may disable exception handler chaining by setting the appropriate option to false:
// <project-root>/firebase.json
{
"react-native": {
"crashlytics_javascript_exception_handler_chaining_enabled": false
}
}Crashlytics non-fatal exceptions native handling
In case you need to log non-fatal (handled) exceptions on the native side (e.g from try catch block), you may use the following static methods:
Android
import io.invertase.firebase.crashlytics.ReactNativeFirebaseCrashlyticsNativeHelper;
//...
try {
//...
} catch (Exception e) {
ReactNativeFirebaseCrashlyticsNativeHelper.recordNativeException(e);
return null;
}iOS
#import <RNFBCrashlytics/RNFBCrashlyticsNativeHelper.h>
//...
@try {
//...
} @catch (NSException *exception) {
NSMutableDictionary * info = [NSMutableDictionary dictionary];
[info setValue:exception.name forKey:@"ExceptionName"];
[info setValue:exception.reason forKey:@"ExceptionReason"];
[info setValue:exception.callStackReturnAddresses forKey:@"ExceptionCallStackReturnAddresses"];
[info setValue:exception.callStackSymbols forKey:@"ExceptionCallStackSymbols"];
[info setValue:exception.userInfo forKey:@"ExceptionUserInfo"];
NSError *error = [[NSError alloc] initWithDomain:yourdomain code:errorcode userInfo:info];
[RNFBCrashlyticsNativeHelper recordNativeError:error];
}Database Usage Index (`docs/database/usage/index.mdx`)
title: Realtime Database next: /database/offline-support previous: /crashlytics/crash-reports
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the database module
yarn add @react-native-firebase/database
# If you're developing your app using iOS, run this command
cd ios/ && pod install && cd ..If you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: getServerTime, setPersistenceEnabled, and setPersistenceCacheSizeBytes are RN-specific. goOnline / goOffline cross the async native bridge. forceLongPolling / forceWebSockets throw — transport is native-controlled.
What does it do
The Realtime Database is a cloud-hosted database. Data is stored as JSON and synchronized in realtime to every connected
client. React Native Firebase provides native integration with the Android & iOS Firebase SDKs, supporting both realtime
data sync and offline capabilities.
To learn more, view the Firebase Realtime Database documentation.
Usage
References
A core concept to understanding Realtime Database are references - a reference to a specific node within your database. A node
can be a specific property or sub-nodes.
To create a Reference, use the ref function:
import { getDatabase, ref } from '@react-native-firebase/database';
const db = getDatabase();
const reference = ref(db, '/users/123');NOTE: To get a reference to a database other than a 'us-central1' default database, you must pass the database URL. You can find your Realtime Database URL in the Realtime Database section of the Firebase console.
import { getDatabase, ref } from '@react-native-firebase/database';
const db = getDatabase(undefined, 'https://<databaseName>.<region>.firebasedatabase.app/');
const reference = ref(db, '/users/123');Reading data
The Realtime Data provides the ability to read the value of a reference as a one-time read, or realtime changes to the node.
When a value is read from the database, the API returns a DataSnapshot.
The snapshot includes information such as whether the reference node exists, it's value or any children the node has and more.
One-time read
To read the value once, use get:
import { getDatabase, ref, get } from '@react-native-firebase/database';
const db = getDatabase();
get(ref(db, '/users/123')).then(snapshot => {
console.log('User data: ', snapshot.val());
});Realtime changes
To setup an active listener to react to any changes to the node and it's children, use onValue:
import { getDatabase, ref, onValue } from '@react-native-firebase/database';
const db = getDatabase();
onValue(ref(db, '/users/123'), snapshot => {
console.log('User data: ', snapshot.val());
});The event handler will be called straight away with the snapshot data, and further called when any changes to the node
occur.
You can unsubscribe by calling the function returned from onValue. This can be used within any useEffect hooks to automatically unsubscribe
when the hook needs to unsubscribe itself:
import React, { useEffect } from 'react';
import { getDatabase, ref, onValue } from '@react-native-firebase/database';
function User({ userId }) {
useEffect(() => {
const db = getDatabase();
const unsubscribe = onValue(ref(db, `/users/${userId}`), snapshot => {
console.log('User data: ', snapshot.val());
});
// Stop listening for updates when no longer required
return () => unsubscribe();
}, [userId]);
}Additional events
The above example demonstrates how to subscribe to events whenever a value within the node changes. In some cases, you
may need to only subscribe to events whenever a child node is added/changed/moved/removed. This can be achieved using
a different listener such as onChildAdded.
If you are listening to a node with many children, only listening to data you care about helps reduce network bandwidth
and speeds up your application.
import React, { useEffect } from 'react';
import { getDatabase, ref, onChildAdded } from '@react-native-firebase/database';
function User({ userId }) {
useEffect(() => {
const db = getDatabase();
const unsubscribe = onChildAdded(ref(db, '/users'), snapshot => {
console.log('A new node has been added', snapshot.val());
});
// Stop listening for updates when no longer required
return () => unsubscribe();
}, [userId]);
}Querying
Realtime Database provides support for basic querying of your data. When a reference node contains children, you can both
order & limit the returned results.
If your application requires more advanced query capabilities, it is recommended you use Cloud Firestore.
Ordering
By default, results are ordered based on the node keys. If however you are using custom keys you can use
the orderByX query constraints with query to order your data.
For example, if all of the nodes children are scalar values (string, number or boolean) you can use orderByValue,
and Firebase will automatically order the results. The example below would return the def node before the abc node:
/*
* {
* 'scores': {
* 'abc: 30,
* 'def': 50,
* }
* }
*/
import { getDatabase, ref, query, orderByValue, get } from '@react-native-firebase/database';
const db = getDatabase();
const scores = get(query(ref(db, 'scores'), orderByValue()));Please note that the ordering will not be respected if you do not use the forEach method provided on the DataSnapshot.
Limiting
You can limit the number of results returned from a query by using limitToFirst or limitToLast query constraints. For example, to limit to the
first 10 results:
import { getDatabase, ref, query, limitToFirst, get } from '@react-native-firebase/database';
const db = getDatabase();
const users = get(query(ref(db, 'users'), limitToFirst(10)));Firebase also provides the ability to return the last set of results in a query via limitToLast.
Instead of limiting to a specific number of documents, you can also start from, or end at a specific reference node value:
import {
getDatabase,
ref,
query,
orderByChild,
startAt,
get,
} from '@react-native-firebase/database';
const db = getDatabase();
await get(query(ref(db, 'users'), orderByChild('age'), startAt(21)));Writing data
The Firebase documentation provides great examples on best
practices on how to structure your data. We highly recommend reading the guide before building out your database.
Setting data
The set function overwrites all of the existing data at that reference node.
The value can be anything; a string, number, object etc:
import { getDatabase, ref, set } from '@react-native-firebase/database';
const db = getDatabase();
set(ref(db, '/users/123'), {
name: 'Ada Lovelace',
age: 31,
}).then(() => console.log('Data set.'));If you set the value to null, Firebase will automatically class the node as removed, and delete it from the database.
Updating data
Rather than overwriting all existing data, the update function provides the ability to update any existing data on the reference node.
Firebase will automatically merge the data depending on what currently exists.
import { getDatabase, ref, update } from '@react-native-firebase/database';
const db = getDatabase();
update(ref(db, '/users/123'), {
age: 32,
}).then(() => console.log('Data updated.'));Pushing data
Currently the examples have only demonstrated working with known reference node keys (e.g. /users/123). In some cases,
you may not have a suitable id or may want Firebase to automatically create a node with a generated key. The push function
returns a ThenableReference, allowing you to observe a node before it is
sent to remote Firebase database.
push will automatically generate a new key if one is not provided:
import { getDatabase, ref, push, set } from '@react-native-firebase/database';
const db = getDatabase();
const newReference = push(ref(db, '/users'));
console.log('Auto generated key: ', newReference.key);
set(newReference, {
age: 32,
}).then(() => console.log('Data updated.'));The keys generated are ordered to the current time, so the list of items returned from Firebase will be chronologically
sorted by default.
Removing data
To remove data, use the remove function:
import { getDatabase, ref, remove } from '@react-native-firebase/database';
await remove(ref(getDatabase(), '/users/123'));Optionally, you can also set the value of a reference node to null to remove it from the database:
import { getDatabase, ref, set } from '@react-native-firebase/database';
await set(ref(getDatabase(), '/users/123'), null);Transactions
Transactions are a way to always ensure a write occurs with the latest information available on the server. Transactions never
partially apply writes & all writes execute at the end of a successful transaction.
Imagine a scenario whereby an app has the ability to "Like" user posts. Whenever a user presses the "Like" button,
the /likes/:postId value (number of likes) on the database increments. Without transactions, we'd first need to
read the existing value and then increment that value in two separate operations.
On a high traffic application, the value on the server could already have changed by the time the operation sets a new value,
causing the actual number to not be consistent.
Transactions remove this issue by atomically updating the value on the server. If the value changes whilst the transaction
is executing, it will retry. This always ensures the value on the server is used rather than the client value.
To execute a new transaction, call runTransaction:
import { getDatabase, ref, runTransaction } from '@react-native-firebase/database';
function onPostLike(postId) {
const db = getDatabase();
const reference = ref(db, `/likes/${postId}`);
return runTransaction(reference, currentLikes => {
if (currentLikes === null) return 1;
return currentLikes + 1;
});
}
// When post "567" is liked
onPostLike('567').then(transaction => {
console.log('New post like count: ', transaction.snapshot.val());
});Once the transaction is successful, a promise is resolved with a value containing whether the operation committed on the remote
database and the new DataSnapshot containing the new value.
Securing data
It is important that you understand how to write rules in your Firebase console to ensure that your data is secure.
Please follow the Firebase Realtime Database documentation on security
Using a secondary database
If the default installed Firebase instance needs to address a different database within the same project, pass the database URL to getDatabase.
For example:
import { getDatabase, ref } from '@react-native-firebase/database';
const db = getDatabase(undefined, 'https://path-to-database.firebaseio.com');
ref(db);Connect to a database of a secondary app
If you want to address a database from a different Firebase project, you will need to create a secondary app first
(Read more on creating a secondary app here: https://rnfirebase.io/app/usage).
For example:
import { initializeApp } from '@react-native-firebase/app';
import { getDatabase, ref } from '@react-native-firebase/database';
// create a secondary app
const secondaryApp = await initializeApp(credentials, config);
const secondaryDb = getDatabase(secondaryApp);
ref(secondaryDb);firebase.json
Enabling persistence
The Realtime Database can be set to persist data on the user application to be used by the SDKs for offline usage
and caching. To enable this functionality, update the database_persistence_enabled key in the firebase.json file:
// <project-root>/firebase.json
{
"react-native": {
"database_persistence_enabled": true
}
}For more on persistence, view the Offline Support documentation.
Firestore Pipelines Index (`docs/firestore/pipelines/index.mdx`)
title: Pipelines next: /firestore/pipelines/current-document previous: /firestore/pagination
Firestore pipeline queries let you run multi-stage read operations (filter, project, aggregate, vector search, and more) against Cloud Firestore using a fluent, composable API. React Native Firebase exposes the same modular pipeline surface as the firebase-js-sdk so you can reuse patterns from web documentation and samples.
Pipeline support in React Native Firebase is marked @beta in TypeScript. APIs may evolve as Firebase ships new pipeline features.
What are pipeline queries?
Traditional Firestore queries are collection-scoped and limited to a single query shape. Pipelines chain stages (for example where, select, aggregate, findNearest) on a source (collection, collection group, documents list, or an existing query). Each stage transforms the result of the previous stage.
Google's upstream resources:
- Get started with pipeline queries
- firebase-js-sdk pipeline reference
- Introducing pipeline operations (Firebase blog, Jan 2026)
For a full list of which firebase-js-sdk exports are available in React Native Firebase today, see SDK compatibility.
Requirements
Firestore Enterprise edition
Pipeline execute() requires a Firestore Enterprise database. Standard edition databases reject pipeline execution. Create an Enterprise database in the Firebase console or with the Firebase CLI before testing pipelines in your project.
Cloud execution (not the local emulator)
The Firestore emulator used for most React Native Firebase e2e tests runs in Standard edition mode and does not faithfully execute pipeline queries. Plan to develop and test pipelines against a live Enterprise database in your Firebase project.
The emulator may gain additional Enterprise pipeline support over time, but React Native Firebase pipeline integration tests today run against a dedicated cloud database (pipelines-e2e on the public testing project), not the local emulator.
Installation
Pipelines ship inside @react-native-firebase/firestore. Install the app and Firestore modules as described in Cloud Firestore usage:
yarn add @react-native-firebase/app @react-native-firebase/firestore
cd ios && pod installExpression helpers and types are imported from the pipelines entry point:
import { getFirestore } from '@react-native-firebase/firestore';
import { field, constant, execute } from '@react-native-firebase/firestore/pipelines';You can also call getFirestore().pipeline() on any Firestore instance to start building a pipeline from a source stage.
Basic example
This example reads documents from a collection, keeps rows where score is at least 10, projects two fields, and sorts by score descending. Adjust the database id and collection path for your Enterprise database.
import { getFirestore } from '@react-native-firebase/firestore';
import { field, execute } from '@react-native-firebase/firestore/pipelines';
const db = getFirestore(); // use a named Enterprise database id if needed
const pipeline = db
.pipeline()
.collection('books')
.where(field('score').greaterThanOrEqual(10))
.select(field('title'), field('score'))
.sort({ ordering: [{ fieldPath: 'score', direction: 'desc' }] });
const snapshot = await execute(pipeline);
snapshot.results.forEach(row => {
console.log(row.data());
});execute() returns a PipelineSnapshot with a results array of pipeline rows. Iterate snapshot.results or access individual entries by index.
Supported stages and sources
React Native Firebase supports these source types:
| Source | Description |
|---|---|
collection |
Documents in a collection path |
collectionGroup |
Documents across a collection id |
database |
Database-scoped pipeline source |
documents |
Explicit document paths |
query |
Pipeline created from an existing Firestore query (createFrom) |
These stage types are available on the pipeline builder:
| Stage | Purpose |
|---|---|
where |
Filter rows |
select |
Project fields |
addFields / removeFields |
Add or drop computed fields |
sort |
Order results |
limit / offset |
Paginate |
aggregate |
Group and reduce |
distinct |
Deduplicate |
findNearest |
Vector similarity search (requires vector index) |
replaceWith |
Replace row shape |
sample |
Random sample |
union |
Combine pipelines |
unnest |
Expand array fields into rows |
Vector search with `findNearest`
The findNearest stage runs vector similarity search over an indexed embedding field. Use the same lowercase distanceMeasure values as the firebase-js-sdk pipeline reference: 'euclidean', 'cosine', or 'dot_product'.
Create a vector index on your Enterprise database before running this query.
import { getFirestore } from '@react-native-firebase/firestore';
import { execute } from '@react-native-firebase/firestore/pipelines';
const db = getFirestore(); // Enterprise database with a vector index on `embedding`
const queryVector = [1.0, 0.0, 0.0];
const snapshot = await execute(
db
.pipeline()
.collection('products')
.findNearest({
field: 'embedding',
vectorValue: queryVector,
distanceMeasure: 'euclidean',
limit: 5,
})
.select('name'),
);
snapshot.results.forEach(row => {
console.log(row.data().name);
});Newer firebase-js-sdk stage helpers such as subcollection and parent are not yet exposed — see SDK compatibility.
Platform notes
| Platform | Runtime | Notes |
|---|---|---|
| Android | Native Firebase Android SDK | Full native pipeline execution |
| iOS | Native Firebase iOS SDK | Some expression helpers are not yet supported on iOS; see compatibility page |
| macOS | firebase-js-sdk (web interop) | Same API shape as web; requires network access to Firestore |
On iOS, pipelines that use unsupported expression functions fail before execution with a clear error listing the function names. The compatibility page lists the current set.
On macOS, pipeline execution goes through the web Firebase SDK bundled for React Native macOS targets. Behavior should match web pipeline queries for the same database and rules.
TypeScript
Pipeline types and expression helpers are exported from @react-native-firebase/firestore/pipelines. The firestore.pipeline() method is augmented on Firestore when you import the firestore module.
Run yarn compare:types in the React Native Firebase repository to see tracked differences between our public types and the firebase-js-sdk pipelines declarations.
Expression helpers
| Helper | Description |
|---|---|
currentDocument() |
Reference the document currently being processed |
ifNull() |
Fallback when a field is null or absent |
switchOn() |
First matching condition / default result |
See Pipeline SDK compatibility for the full firebase-js-sdk parity matrix.
Next steps
- Review SDK compatibility before porting firebase-js-sdk pipeline samples.
- Read Firebase's get started guide for index setup, vector search, and security rules considerations.
- For classic collection queries, continue with Cloud Firestore usage.
Firestore Usage Index (`docs/firestore/usage/index.mdx`)
title: Cloud Firestore next: /firestore/emulator previous: /auth/multi-factor-auth
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the firestore module
yarn add @react-native-firebase/firestore
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
If you have started to receive a app:mergeDexDebug error after adding Cloud Firestore, please read the
Enabling Multidex documentation for more information on how to resolve this error.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK); macOS via firebase-js-sdk web interop |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: IndexedDB persistence and memoryLocalCache / persistentLocalCache are web only. Native persistence is controlled by the iOS/Android Firestore SDK. initializeFirestore is async on React Native.
What does it do
Firestore is a flexible, scalable NoSQL cloud database to store and sync data. It keeps your data in sync across client
apps through realtime listeners and offers offline support so you can build responsive apps that work regardless of network
latency or Internet connectivity.
Usage
Collections & Documents
Cloud Firestore stores data within "documents", which are contained within "collections", and documents can also contain
collections. For example, we could store a list of our users documents within a "Users" collection. The collection function
allows us to reference a collection within our code:
import { collection, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
const usersCollection = collection(db, 'Users');The collection function returns a CollectionReference class, which provides
properties and methods to query and fetch the data from Cloud Firestore. We can also directly reference a single document
on the collection by calling the doc function:
import { collection, doc, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
// Get user document with an ID of ABC
const userDocument = doc(collection(db, 'Users'), 'ABC');The doc function returns a DocumentReference.
A document can contain different types of data, including scalar values (strings, booleans, numbers), arrays (lists) and
objects (maps) along with specific Cloud Firestore data such as Timestamps,
GeoPoints, Bytes and more.
Read Data
Cloud Firestore provides the ability to read the value of a collection or document. This can be read one-time, or provide
realtime updates when the data within a query changes.
One-time read
To read a collection or document once, call getDocs on a CollectionReference
or getDoc on a DocumentReference:
import { collection, doc, getDoc, getDocs, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
const users = await getDocs(collection(db, 'Users'));
const user = await getDoc(doc(collection(db, 'Users'), 'ABC'));Realtime changes
To setup an active listener to react to any changes to the query, call onSnapshot with an event handler callback.
For example, to watch the entire "Users" collection for when any documents are changed (removed, added, modified):
import { collection, getFirestore, onSnapshot } from '@react-native-firebase/firestore';
const db = getFirestore();
function onResult(QuerySnapshot) {
console.log('Got Users collection result.');
}
function onError(error) {
console.error(error);
}
onSnapshot(collection(db, 'Users'), onResult, onError);onSnapshot also returns a function, allowing you to unsubscribe from events. This can be used within anyuseEffect hooks to automatically unsubscribe when the hook needs to unsubscribe itself:
import React, { useEffect } from 'react';
import { collection, doc, getFirestore, onSnapshot } from '@react-native-firebase/firestore';
const db = getFirestore();
function User({ userId }) {
useEffect(() => {
const subscriber = onSnapshot(doc(collection(db, 'Users'), userId), documentSnapshot => {
console.log('User data: ', documentSnapshot.data());
});
// Stop listening for updates when no longer required
return () => subscriber();
}, [userId]);
}Realtime changes via onSnapshot can be applied to both collections and documents.
Snapshots
Once a query has returned a result, Firestore returns either a QuerySnapshot (for
collection queries) or a DocumentSnapshot (for document queries). These snapshots
provide the ability to view the data, view query metadata (such as whether the data was from local cache), whether the
document exists or not and more.
`QuerySnapshot`
A QuerySnapshot returned from a collection query allows you to inspect the collection,
such as how many documents exist within it, access to the documents within the collection, any changes since the last query
and more.
To access the documents within a QuerySnapshot, call the forEach method:
import { collection, getDocs, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
getDocs(collection(db, 'Users')).then(querySnapshot => {
console.log('Total users: ', querySnapshot.size);
querySnapshot.forEach(documentSnapshot => {
console.log('User ID: ', documentSnapshot.id, documentSnapshot.data());
});
});Each child document of a QuerySnapshot is a QueryDocumentSnapshot, which
allows you to access specific information about a document (see below).
`DocumentSnapshot`
A DocumentSnapshot is returned from a query to a specific document, or as part
of the documents returned via a QuerySnapshot. The snapshot provides the ability
to view a documents data, metadata and whether a document actually exists.
To view a documents data, call the data method on the snapshot:
import { collection, doc, getDoc, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
getDoc(doc(collection(db, 'Users'), 'ABC')).then(documentSnapshot => {
console.log('User exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('User data: ', documentSnapshot.data());
}
});A snapshot also provides a helper function to easily access deeply nested data within a document. Call the get method
with a dot-notated path:
import { collection, doc, getDoc, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
function getUserZipCode(documentSnapshot) {
return documentSnapshot.get('info.address.zipcode');
}
getDoc(doc(collection(db, 'Users'), 'ABC'))
.then(documentSnapshot => getUserZipCode(documentSnapshot))
.then(zipCode => {
console.log('Users zip code is: ', zipCode);
});Querying
Cloud Firestore offers advanced capabilities for querying collections.
Filtering
To filter documents within a collection, pass where constraints to query. Filtering supports
equality checks and "in" queries. For example, to filter users where their age is greater or equal than 18 years old:
import { collection, getDocs, getFirestore, query, where } from '@react-native-firebase/firestore';
const db = getFirestore();
getDocs(query(collection(db, 'Users'), where('age', '>=', 18))).then(querySnapshot => {
/* ... */
});Cloud Firestore also supports array membership queries. For example, to filter users who speak both English (en) or
French (fr), use the in filter:
getDocs(query(collection(db, 'Users'), where('languages', 'in', ['en', 'fr']))).then(
querySnapshot => {
/* ... */
},
);To learn more about all of the querying capabilities Cloud Firestore has to offer, view the
Firebase documentation.
You can combine multiple filters using and() and or() composite constraints.
For example:
import {
and,
collection,
getDocs,
getFirestore,
or,
query,
where,
} from '@react-native-firebase/firestore';
const db = getFirestore();
const snapshot = await getDocs(
query(
collection(db, 'Users'),
where('user', '==', 'Tim'),
where('email', '==', '[email protected]'),
),
);You can use the and() function to make logical AND queries:
const snapshot = await getDocs(
query(
collection(db, 'Users'),
and(where('user', '==', 'Tim'), where('email', '==', '[email protected]')),
),
);You can use the or() function to make logical OR queries:
const snapshot = await getDocs(
query(
collection(db, 'Users'),
or(
and(where('user', '==', 'Tim'), where('email', '==', '[email protected]')),
and(where('user', '==', 'Dave'), where('email', '==', '[email protected]')),
),
),
);For an understanding of what queries are possible, please consult the query limitation documentation on the official
Firebase Firestore documentation.
Limiting
To limit the number of documents returned from a query, use the limit constraint:
import {
collection,
getDocs,
getFirestore,
limit,
query,
where,
} from '@react-native-firebase/firestore';
const db = getFirestore();
getDocs(query(collection(db, 'Users'), where('age', '>=', 18), limit(20))).then(querySnapshot => {
/* ... */
});The above example both filters the users by age and limits the documents returned to 20.
Ordering
To order the documents by a specific value, use the orderBy constraint:
import {
collection,
getDocs,
getFirestore,
orderBy,
query,
} from '@react-native-firebase/firestore';
const db = getFirestore();
getDocs(query(collection(db, 'Users'), orderBy('age', 'desc'))).then(querySnapshot => {
/* ... */
});The above example orders all user in the snapshot by age in descending order.
Start/End
To start and/or end the query at a specific point within the collection, you can pass either a value to startAt,endAt, startAfter or endBefore. You must specify an order to use pointers, for example:
import {
collection,
endAt,
getDocs,
getFirestore,
orderBy,
query,
startAt,
} from '@react-native-firebase/firestore';
const db = getFirestore();
getDocs(query(collection(db, 'Users'), orderBy('age', 'desc'), startAt(18), endAt(30))).then(
querySnapshot => {
/* ... */
},
);The above query orders the users by age in descending order, but only returns users whose age is between 18 and 30.
You can further specify a DocumentSnapshot instead of a specific value. For example:
import {
collection,
doc,
getDoc,
getDocs,
getFirestore,
orderBy,
query,
startAt,
} from '@react-native-firebase/firestore';
const db = getFirestore();
const userDocumentSnapshot = await getDoc(doc(collection(db, 'Users'), 'DEF'));
getDocs(query(collection(db, 'Users'), orderBy('age', 'desc'), startAt(userDocumentSnapshot))).then(
querySnapshot => {
/* ... */
},
);The above query orders the users by age in descending order, however only returns documents whose order starts at the user
with an ID of DEF.
Query Limitations
Cloud Firestore does not support the following types of queries:
- Queries with range filters on different fields, as described in the previous section.
Writing Data
The Firebase documentation provides great examples
on best practices on how to structure your data. We highly recommend reading the guide before building out your database.
For a more in-depth look at what is possible when writing data to Firestore please refer to this documentation
Adding documents
To add a new document to a collection, use addDoc with a CollectionReference:
import { addDoc, collection, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
addDoc(collection(db, 'Users'), {
name: 'Ada Lovelace',
age: 30,
}).then(() => {
console.log('User added!');
});addDoc adds the new document to your collection with a random unique ID. If you'd like to specify your own ID,
call setDoc with a DocumentReference instead:
import { collection, doc, getFirestore, setDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
setDoc(doc(collection(db, 'Users'), 'ABC'), {
name: 'Ada Lovelace',
age: 30,
}).then(() => {
console.log('User added!');
});Updating documents
The setDoc example above replaces any existing data on a given DocumentReference.
if you'd like to update a document instead, use updateDoc:
import { collection, doc, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(collection(db, 'Users'), 'ABC'), {
age: 31,
}).then(() => {
console.log('User updated!');
});The method also provides support for updating deeply nested values via dot-notation:
import { collection, doc, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(collection(db, 'Users'), 'ABC'), {
'info.address.zipcode': 94040,
}).then(() => {
console.log('User updated!');
});Field values
Cloud Firestore supports storing and manipulating values on your database, such as Timestamps,
GeoPoints, Bytes and array management.
To store GeoPoint values, provide the latitude and longitude to a new instance of the
class:
import { doc, GeoPoint, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(db, 'users', 'ABC'), {
'info.address.location': new GeoPoint(53.483959, -2.244644),
});To store raw Bytes (for example of a Base64 image string), provide the string to the staticfromBase64String method on the class:
import { Bytes, doc, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(db, 'users', 'ABC'), {
'info.avatar': Bytes.fromBase64String('data:image/png;base64,iVBOR...'),
});When storing timestamps, it is recommended you use serverTimestamp(). When written to the database, the Firebase servers will write a new timestamp based on their time, rather than the clients. This helps
resolve any data consistency issues with different client timezones:
import { doc, getFirestore, serverTimestamp, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(db, 'users', 'ABC'), {
createdAt: serverTimestamp(),
});Cloud Firestore also allows for storing arrays. To help manage the values with an array (adding or removing), the API
exposes arrayUnion and arrayRemove helpers.
To add a new value to an array (if value does not exist, will not add duplicate values):
import { arrayUnion, doc, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(db, 'users', 'ABC'), {
fcmTokens: arrayUnion('ABCDE123456'),
});To remove a value from the array (if the value exists):
import { arrayRemove, doc, getFirestore, updateDoc } from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(db, 'users', 'ABC'), {
fcmTokens: arrayRemove('ABCDE123456'),
});Removing data
You can delete documents within Cloud Firestore using the deleteDoc method with a DocumentReference:
import { deleteDoc, doc, getFirestore } from '@react-native-firebase/firestore';
const userDocRef = doc(getFirestore(), 'users/ExampleUser');
deleteDoc(userDocRef).then(() => {
console.log('User deleted!');
});At this time, you cannot delete an entire collection without use of a Firebase Admin SDK.
If a document contains any sub-collections, these will not be deleted from database. You must delete
any sub-collections yourself.
If you need to remove a specific property with a document, rather than the document itself, you can use deleteField:
import {
collection,
deleteField,
doc,
getFirestore,
updateDoc,
} from '@react-native-firebase/firestore';
const db = getFirestore();
updateDoc(doc(collection(db, 'Users'), 'ABC'), {
fcmTokens: deleteField(),
});Transactions
Transactions are a way to always ensure a write occurs with the latest information available on the server. Transactions
never partially apply writes & all writes execute at the end of a successful transaction.
Transactions are useful when you want to update a field's value based on its current value, or the value of some other field.
If you simply want to write multiple documents without using the document's current state, a batch write would be more appropriate.
When using transactions, note that:
- Read operations must come before write operations.
- A function calling a transaction (transaction function) might run more than once if a concurrent edit affects a document that the transaction reads.
- Transaction functions should not directly modify application state (return a value from the
updateFunction). - Transactions will fail when the client is offline.
Imagine a scenario whereby an app has the ability to "Like" user posts. Whenever a user presses the "Like" button,
a "likes" value (number of likes) on a "Posts" collection document increments. Without transactions, we'd first need to read
the existing value and then increment that value in two separate operations.
On a high traffic application, the value on the server could already have changed by the time the operation sets a new value,
causing the actual number to not be consistent.
Transactions remove this issue by atomically updating the value on the server. If the value changes whilst the transaction
is executing, it will retry. This always ensures the value on the server is used rather than the client value.
To execute a new transaction, call runTransaction:
import { doc, getFirestore, runTransaction } from '@react-native-firebase/firestore';
const db = getFirestore();
function onPostLike(postId) {
// Create a reference to the post
const postReference = doc(db, 'posts', postId);
return runTransaction(db, async transaction => {
// Get post data first
const postSnapshot = await transaction.get(postReference);
if (!postSnapshot.exists) {
throw 'Post does not exist!';
}
transaction.update(postReference, {
likes: postSnapshot.data().likes + 1,
});
});
}
onPostLike('ABC')
.then(() => console.log('Post likes incremented via a transaction'))
.catch(error => console.error(error));Batch write
If you do not need to read any documents in your operation set, you can execute multiple write operations as a single batch
that contains any combination of setDoc, updateDoc, or deleteDoc operations. A batch of writes completes atomically and can
write to multiple documents.
First, create a new batch instance via writeBatch, perform operations on the batch and finally commit it once ready.
The example below shows how to delete all documents in a collection in a single operation:
import { collection, getDocs, getFirestore, writeBatch } from '@react-native-firebase/firestore';
const db = getFirestore();
async function massDeleteUsers() {
// Get all users
const usersQuerySnapshot = await getDocs(collection(db, 'Users'));
// Create a new batch instance
const batch = writeBatch(db);
usersQuerySnapshot.forEach(documentSnapshot => {
batch.delete(documentSnapshot.ref);
});
return batch.commit();
}
massDeleteUsers().then(() => console.log('All users deleted in a single batch operation.'));Secure your data
It is important that you understand how to write rules in your Firebase console to ensure that your data is secure. Please
follow the Firebase Firestore documentation on security.
Offline Capabilities
Firestore provides out of the box support for offline capabilities. When reading and writing data, Firestore uses a local
database which synchronizes automatically with the server. Firestore functionality continues when users are offline, and
automatically handles data migration to the server when they regain connectivity.
This functionality is enabled by default, however it can be disabled if you need it to be disabled (e.g. on apps containing
sensitive information). initializeFirestore must be called before any Firestore interaction is performed, otherwise it will only take effect on the next app launch:
import { getApp } from '@react-native-firebase/app';
import { initializeFirestore } from '@react-native-firebase/firestore';
async function bootstrap() {
await initializeFirestore(getApp(), {
persistence: false, // disable offline persistence
});
}Data bundles
Cloud Firestore data bundles are static data files built by you from Cloud Firestore document and query snapshots,
and published by you on a CDN, hosting service or other solution. Once a bundle is loaded, a client app can query documents
from the local cache or the backend.
To load and query data bundles, use loadBundle and namedQuery:
import {
getDocsFromCache,
getFirestore,
loadBundle,
namedQuery,
} from '@react-native-firebase/firestore';
const db = getFirestore();
// load the bundle contents
const response = await fetch('https://api.example.com/bundles/latest-stories');
const bundle = await response.text();
await loadBundle(db, bundle);
// query the results from the cache
// note: use getDocsFromCache to query the local cache only
const storiesQuery = await namedQuery(db, 'latest-stories-query');
if (storiesQuery) {
const snapshot = await getDocsFromCache(storiesQuery);
}You can build data bundles with the Admin SDK. For more information about building and serving data bundles, see Firebase Firestore main documentation on Data bundles as well as their "Bundle Solutions" page
Functions Usage Index (`docs/functions/usage/index.mdx`)
title: Cloud Functions next: /functions/writing-deploying-functions previous: /firestore/pipelines/sdk-compatibility
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the functions module
yarn add @react-native-firebase/functions
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required — since v24 for Functions, and for all native modules from v26. See Migrating to v26 and Migrating to v24 — Cloud Functions. |
What does it do
Firebase Cloud Functions let you automatically run backend code in response to events triggered by Firebase features and
HTTPS requests. Your code is stored in Google's cloud and runs in a managed environment. There's no need to manage and
scale your own servers.
After you write and deploy a function, Google's servers begin to manage the function immediately. You can fire the function
directly with an HTTP request, via the Cloud Functions module, or in the case of background functions, Google's servers will listen for events and run
the function when it is triggered.
For more information on use cases, view the Firebase Cloud Functions documentation.
Usage
The Cloud Functions module provides the functionality to directly trigger deployed HTTPS callable functions, without worrying
about security or implementing a HTTP request library.
Functions deployed to Firebase have unique names, allowing you to easily identify which endpoint you wish to send a request to.
To learn more about deploying Functions to Firebase, view the Writing & Deploying Functions documentation.
Using an emulator
Whilst developing your application with Cloud Functions, it is possible to run the functions inside of a local emulator.
To call the emulated functions in the default region, call the useEmulator method exposed by the library:
import { connectFunctionsEmulator, getFunctions } from '@react-native-firebase/functions';
if (__DEV__) {
connectFunctionsEmulator(getFunctions(), 'localhost', 5001);
}If your functions are deployed on a different region, then please see Region-specific Functions
Calling an endpoint
Assuming we have a deployed a callable endpoint named listProducts, to call the endpoint the library exposes ahttpsCallable method. For example:
// Deployed HTTPS callable
exports.listProducts = functions.https.onCall(() => {
return [
/* ... */
// Return some data
];
});Within the React Native application, the list of products returned can be directly accessed:
import { getFunctions, httpsCallable } from '@react-native-firebase/functions';
function App() {
const [loading, setLoading] = useState(true);
const [products, setProducts] = useState([]);
useEffect(() => {
httpsCallable(getFunctions(), 'listProducts')().then(response => {
setProducts(response.data);
setLoading(false);
});
}, []);
if (loading) {
return null;
}
// ...
}Region-specific Functions
If you need to deploy Functions in a region other than the default one, modified statements need to be used.
import {
connectFunctionsEmulator,
getFunctions,
httpsCallable,
} from '@react-native-firebase/functions';
import { getApp } from '@react-native-firebase/app';
connectFunctionsEmulator(getFunctions(getApp(), 'region_name'), 'localhost', 5001);
httpsCallable(getFunctions(getApp(), 'region_name'), 'listProducts')({ abc: 123 }).then();In App Messaging Usage Index (`docs/in-app-messaging/usage/index.mdx`)
title: In App Messaging next: /installations/usage previous: /database/presence-detection
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
This module also requires that the @react-native-firebase/analytics module is already setup and installed. To install the "analytics" module, view it's Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the in-app-messaging module
yarn add @react-native-firebase/in-app-messaging
# If you're developing your app using iOS, run this command
cd ios/ && pod installNote: in-app-messaging requires a minimum android gradle plugin version of 3.5.4 to compile or you will see AAPT errors regarding unexpected XML with <queries> elements. However, [email protected] still ships with a default of 3.5.3. If you have not already, you must update the line classpath("com.android.tools.build:gradle:3.5.3")in android/build.gradle to a minimum of 3.5.4 for android builds to work.
If you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
React Native only: There is no firebase-js-sdk web equivalent for In-App Messaging.
What does it do
Firebase In-App Messaging helps you to engage your apps active users by sending them targeted, contextual messages that encourage
them to use key app features. For example, you could send an in-app message to get users to subscribe, watch a video,
complete a level, or buy an item. You can customize messages as cards, banners, modals, or images, and set up triggers
so that they appear exactly when they'd benefit your users most.
React Native Firebase provides support for both native Android & iOS integration with a simple JavaScript API.
Usage
Most of the set up occurs on Firebase Console in theIn-App Messaging tab. You can create campaigns and customize elements such as Image, Banner, Modal & Cards to appear on
predefined events (e.g. purchase). This involves no code for the developer to implement. Any published campaigns from the
Firebase Console are automatically handled and displayed on your user's device.
This module provides a JavaScript API to allow greater control of the displaying of these messages.
Limitations
According to github issue https://github.com/firebase/firebase-ios-sdk/issues/4768 Firebase In-App Messaging allows only 1 campaign per day on app foreground or app launch. This limit is to prevent you from accidentally overwhelming your users with non-contextually appropriate messages. However, if you use the contextual triggers (for example: Analytics event or programmatically triggered in-app-messaging campaigns), there is no daily rate limit.
Displaying Messages
The setMessagesDisplaySuppressed method allows you to control when messages can/cannot be displayed. Below illustrates
a use case for controlling the flow of messages:
The suppressed state is not persisted between restarts, so ensure it is called as early as possible.
import {
getInAppMessaging,
setMessagesDisplaySuppressed,
} from '@react-native-firebase/in-app-messaging';
async function bootstrap() {
await setMessagesDisplaySuppressed(getInAppMessaging(), true);
}
async function onSetup(user) {
await setupUser(user);
await setMessagesDisplaySuppressed(getInAppMessaging(), false);
}firebase.json
Disable collection of data
In App Messaging can be further configured to enable or disable automatic data collection for Firebase In-App Messaging.
This is useful for opt-in-first data flows, for example when dealing with GDPR compliance. This can be overridden in JavaScript.
This is possible by setting the below noted property on the firebase.json file at the root of your project directory.
// <project-root>/firebase.json
{
"react-native": {
"in_app_messaging_auto_collection_enabled": false
}
}Installations Usage Index (`docs/installations/usage/index.mdx`)
title: Installations next: /remote-config/usage previous: /in-app-messaging/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app"
module, view the Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the installations module
yarn add @react-native-firebase/installations
# If you're developing your app using iOS, run this command
cd ios/ && pod installPlatform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
React Native only: There is no firebase-js-sdk web equivalent for Installations.
What does it do
The Firebase installations service:
- provides a unique identifier for a Firebase installation
- provides an auth token for a Firebase installation
- provides an API to perform GDPR-compliant deletion of a Firebase installation.
Each configured FirebaseApp has a corresponding single instance of Installations. An instance of the class provides access to the installation info for the FirebaseApp as well as the ability to delete it. A Firebase Installation is unique by FirebaseApp.name and FirebaseApp.options.googleAppID
Usage
Please see the API Reference for detailed usage information on the available APIs
Messaging Usage Index (`docs/messaging/usage/index.mdx`)
title: Cloud Messaging next: /messaging/usage/ios-setup previous: /functions/writing-deploying-functions
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the messaging module
yarn add @react-native-firebase/messaging
# If you're developing your app using iOS, run this command
cd ios/ && pod installiOS requires further configuration before you can start receiving and sending
messages through Firebase. Read the documentation on how to setup iOS with Firebase Cloud Messaging.
Use of the
sendMessage()API and it's associated listeners requires a customXMPPserver. Read the documentation on how to Messaging with XMPP.
If you're using an older version of React Native without auto-linking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Expo
iOS - Notifications entitlement
Since Expo SDK51, Notifications entitlement is no longer always added to iOS projects during prebuild. If your project uses push notifications, you may need to add the aps-environment entitlement to your app config:
{
"expo": {
"ios": {
"entitlements": {
"aps-environment": “production”
}
}
}
}iOS - Remote notification
If you require remote notification on Expo, you can also add this to your Expo app.json or app.config.js
{
"expo": {
"ios": {
"infoPlist": {
"UIBackgroundModes": ["remote-notification"]
}
}
}
}Android - Google Play Notification Delegation
If you use the REST v1 APIs (used by the Firebase admin SDKs) and your app is running on Android Q+ with current Google Play services, Google implemented "Notification Delegation" for messages. Notification delegation is not currently compatible with react-native-firebase. Specifically, if your notifications are delegated via proxy to Play Services, then your messaging listeners will not be called.
To work around this incompatibility, react-native-firebase disables notification delegation by default currently, using the AndroidManifest.xml method listed as one of the options described here: https://firebase.google.com/docs/cloud-messaging/android/message-priority#proxy.
You may re-enable notification delegation if your use case requires it and you can accept the messaging listener methods not executing for delegated messages by altering the firebase.json setting messaging_android_notification_delegation_enabled to true.
You may also use the new messaging APIs to get and set the notification delegation state for the app, as desired.
Installation ID messaging (optional)
Firebase Installation ID (FID) registration (register / onRegistered) is available but off by default.
For the migration path (API mapping, opt-in, error codes, checklist), see
Migrating to Installation ID.
Deep usage samples (native keys, Expo plugin, listeners): Installation ID messaging.
For bare React Native, opt in via firebase.json:
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_installation_id_enabled": true
}
}For Expo, use the plugin prop (or set the Android / iOS keys manually — see
Installation ID messaging):
{
"expo": {
"plugins": [
[
"@react-native-firebase/messaging",
{
"installationIdEnabled": true,
"android": {
"notificationIcon": "./assets/notification_icon.png",
"notificationColor": "#ffffff"
}
}
]
]
}
}messaging_installation_id_enabled / installationIdEnabled: true map to Android meta-datafirebase_messaging_installation_id_enabled and iOS FirebaseMessagingInstallationIdEnabled.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: getAPNSToken / setAPNSToken are iOS only. FCM foreground/background listeners use the legacy native event proxy (same runtime behavior as pre-v26). See Migrating to v26 — Platform behavior differences.
What does it do
React Native Firebase provides native integration of Firebase Cloud Messaging (FCM) for both Android & iOS. FCM is a cost
free service, allowing for server-device and device-device communication. The React Native Firebase Messaging module provides
a simple JavaScript API to interact with FCM.
The module also provides basic support for displaying local notifications, to learn more view the Notifications documentation.
Usage
iOS - Requesting permissions
Deprecated:
requestPermission,hasPermission, andAuthorizationStatusare deprecated. Use react-native-permissions or expo-notifications instead. See issue #6283.
iOS prevents messages containing notification (or 'alert') payloads from being displayed unless you have received explicit permission from the user.
To learn more about local notifications, view the Notifications documentation.
This module provides a requestPermission method which triggers a native permission dialog requesting the user's permission:
import {
getMessaging,
requestPermission,
AuthorizationStatus,
} from '@react-native-firebase/messaging';
async function requestUserPermission() {
const messaging = getMessaging();
const authStatus = await requestPermission(messaging);
const enabled =
authStatus === AuthorizationStatus.AUTHORIZED || authStatus === AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
}The permissions API for iOS provides much more fine-grain control over permissions and how they're handled within your
application. To learn more, view the advanced iOS Permissions documentation.
Android - Requesting permissions
Deprecated:
requestPermissionandhasPermissionare deprecated no-ops on Android API level 32 and below. Use react-native-permissions or expo-notifications for notification permission requests on API level 33+. See issue #6283.
On Android API level 32 and below, you do not need to request user permission. This method can still be called on Android devices; however, and will always resolve successfully. For API level 33+ you will need to request the permission manually using either the built-in react-native PermissionsAndroid APIs or a related module such as react-native-permissions or expo-notifications
import {PermissionsAndroid} from 'react-native';
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);Receiving messages
FCM messages can be sent to real Android/iOS devices and Android emulators (iOS simulators however do not handle cloud messages) via a number of methods (see below).
A message is simply a payload of data which can be used however you see fit within your application.
Common use-cases for handling messages could be:
- Displaying a notification (see Notifications).
- Syncing message data silently on the device (e.g. via
AsyncStorage). - Updating the application's UI.
To learn about how to send messages to devices from your own server setup, view the
Server Integration documentation.
Depending on the devices state, incoming messages are handled differently by the device and module. To understand these
scenarios, it is first important to establish the various states a device can be in:
| State | Description |
|---|---|
| Foreground | When the application is open and in view. |
| Background | When the application is open, however in the background (minimized). This typically occurs when the user has pressed the "home" button on the device or has switched to another app via the app switcher. |
| Quit | When the device is locked or application is not active or running. The user can quit an app by "swiping it away" via the app switcher UI on the device. |
The user must have opened the app before messages can be received. If the user force quits the app from the device settings, it must be re-opened again before receiving messages.
Depending on the contents of the message, it's important to understand both how the device will handle the message (e.g. display a notification, or even ignore it) and also how the library sends events to your own listeners.
Message handlers
The device state and message contents determines which handler will be called:
| Foreground | Background | Quit | |
|---|---|---|---|
| Notification | onMessage |
setBackgroundMessageHandler |
setBackgroundMessageHandler |
| Notification + Data | onMessage |
setBackgroundMessageHandler |
setBackgroundMessageHandler |
| Data | onMessage |
setBackgroundMessageHandler (see below) |
setBackgroundMessageHandler (see below) |
In cases where the message is data-only and the device is in the background or quit, both Android & iOS treat the message
as low priority and will ignore it (i.e. no event will be sent). You can however increase the priority by setting theprioritytohigh(Android) andcontent-availabletotrue(iOS) properties on the payload.On iOS in cases where the message is data-only and the device is in the background or quit, the message will be delayed
until the background message handler is registered via setBackgroundMessageHandler, signaling the application's javascript
is loaded and ready to run.
To learn more about how to send these options in your message payload, view the Firebase documentation for your FCM API implementation.
Notifications
The device state and message contents can also determine whether a Notification will be displayed:
| Foreground | Background | Quit | |
|---|---|---|---|
| Notification | Notification: ❌ | Notification: ✅ | Notification: ✅ |
| Notification + Data | Notification: ❌ | Notification: ✅ | Notification: ✅ |
| Data | Notification: ❌ | Notification: ❌ | Notification: ❌ |
Foreground state messages
To listen to messages in the foreground, call the onMessage method inside of your application code. Code
executed via this handler has access to React context and is able to interact with your application (e.g. updating the state or UI).
For example, the React Native Alert API could be used to display a new Alert
each time a message is delivered'
import React, { useEffect } from 'react';
import { Alert } from 'react-native';
import { getMessaging, onMessage } from '@react-native-firebase/messaging';
function App() {
useEffect(() => {
const messaging = getMessaging();
const unsubscribe = onMessage(messaging, async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}, []);
}The remoteMessage property contains all of the information about the message sent to the device from FCM, including
any custom data (via the data property) and notification data. To learn more, view the RemoteMessage
API reference.
If the RemoteMessage payload contains a notification property when sent to the onMessage handler, the device
will not show any notification to the user. Instead, you could trigger a local notification
or update the in-app UI to signal a new notification.
Background & Quit state messages
Note: If you use @notifee/react-native, since v7.0.0,
onNotificationOpenedAppandgetInitialNotificationwill no longer trigger as notifee will handle the event.
When the application is in a background or quit state, the onMessage handler will not be called when receiving messages.
Instead, you need to setup a background callback handler via the setBackgroundMessageHandler method.
To setup a background handler, call the setBackgroundMessageHandler outside of your application logic as early as possible:
// index.js
import { AppRegistry } from 'react-native';
import { getMessaging, setBackgroundMessageHandler } from '@react-native-firebase/messaging';
import App from './App';
const messaging = getMessaging();
// Register background handler
setBackgroundMessageHandler(messaging, async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
AppRegistry.registerComponent('app', () => App);The handler must return a promise once your logic has completed to free up device resources. It must not attempt to update
any UI (e.g. via state) - you can however perform network requests, update local storage etc.
The remoteMessage property contains all of the information about the message sent to the device from FCM, including
any custom data via the data property. To learn more, view the RemoteMessage
API reference.
If the RemoteMessage payload contains a notification property when sent to the setBackgroundMessageHandler handler, the device
will have displayed a notification to the user.
Data-only messages
When an incoming message is "data-only" (contains no notification option), both Android & iOS regard it as low priority
and will prevent the application from waking (ignoring the message). To allow data-only messages to trigger the background
handler, you must set the "priority" to "high" on Android, and enable the content-available flag on iOS. For example,
if using the Node.js firebase-admin package to send a message:
admin.messaging().sendToDevice(
[], // device fcm tokens...
{
data: {
owner: JSON.stringify(owner),
user: JSON.stringify(user),
picture: JSON.stringify(picture),
},
},
{
// Required for background/quit data-only messages on iOS
contentAvailable: true,
// Required for background/quit data-only messages on Android
priority: 'high',
},
);For iOS specific "data-only" messages, the message must include the appropriate APNs headers as well as the content-available flag in order to trigger the background handler. For example, if using the Node.js firebase-admin package to send a "data-only" message to an iOS device:
admin.messaging().send({
data: {
//some data
},
apns: {
payload: {
aps: {
contentAvailable: true,
},
},
headers: {
'apns-push-type': 'background',
'apns-priority': '5',
'apns-topic': '', // your app bundle identifier
},
},
//must include token, topic, or condition
//token: //device token
//topic: //notification topic
//condition: //notification condition
});View the Sending Notification Requests to APNs documentation to learn more about APNs headers.
These options can be applied to all FCM messages. View the Server Integration documentation
to learn more about other available SDKs.
Background Application State
Although the library supports handling messages in background/quit states, the underlying implementation on how this works is different on Android & iOS.
On Android, a Headless JS task (an Android only feature) is created that runs separately to your main React component; allowing your background handler code to run without mounting your root component.
On iOS however, when a message is received the device silently starts your application in a background state. At this point, your background handler (via setBackgroundMessageHandler) is triggered, but your root React component also gets mounted. This can be problematic for some users since any side-effects will be called inside of your app (e.g. useEffects, analytics events/triggers etc). To get around this problem,
you can configure your AppDelegate.m file (see instructions below) to inject a isHeadless prop into your root component. Use this property to conditionally render null ("nothing") if your app is launched in the background:
// index.js
import { AppRegistry } from 'react-native';
import { getMessaging, setBackgroundMessageHandler } from '@react-native-firebase/messaging';
const messaging = getMessaging();
// Handle background messages using setBackgroundMessageHandler
setBackgroundMessageHandler(messaging, async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
// Check if app was launched in the background and conditionally render null if so
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
// Render the app component on foreground launch
return <App />;
}
// Your main application component defined here
function App() {
// Your application
}
AppRegistry.registerComponent('app', () => HeadlessCheck);To inject a isHeadless prop into your app, please update your AppDelegate.m file as instructed below:
// add this import statement at the top of your `AppDelegate.m` file
#import "RNFBMessagingModule.h"
// in "(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions" method
// Use `addCustomPropsToUserProps` to pass in props for initialization of your app
// Or pass in `nil` if you have none as per below example
// For `withLaunchOptions` please pass in `launchOptions` object
// and use it to set `self.initialProps` (available with react-native >= 0.71.1, older versions need a more difficult style, upgrading is recommended)
self.initialProps = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];- For projects that use react-native-navigation (or if you just don't want to mess with your launchProperties) you can use the
getIsHeadlessmethod (iOS only) from messaging like so:
import { getMessaging, getIsHeadless } from '@react-native-firebase/messaging';
const messaging = getMessaging();
getIsHeadless(messaging).then(isHeadless => {
// do sth with isHeadless
});On Android, the isHeadless prop will not exist.
iOS Background Limitation
On iOS devices, the user is able to toggle Background App Refresh in device's Settings. Furthermore, the Background App Refresh setting will automatically be off if the device is in low power mode.
If the iOS Background App Refresh mode is off, your handler configured in setBackgroundMessageHandler will not be triggered.
Topics
Topics are a mechanism which allow a device to subscribe and unsubscribe from named PubSub channels, all managed via FCM.
Rather than sending a message to a specific device by FCM token, you can instead send a message to a topic and any
devices subscribed to that topic will receive the message.
Topics allow you to simplify FCM server integration as you do not need to keep a store of
device tokens. There are however some things to keep in mind about topics:
- Messages sent to topics should not contain sensitive or private information. Do not create a topic for a specific user
to subscribe to. - Topic messaging supports unlimited subscriptions for each topic.
- One app instance can be subscribed to no more than 2000 topics.
- The frequency of new subscriptions is rate-limited per project. If you send too many subscription requests in a short
period of time, FCM servers will respond with a 429 RESOURCE_EXHAUSTED ("quota exceeded") response. Retry with exponential backoff. - A server integration can send a single message to multiple topics at once. This however is limited to 5 topics.
To learn more about how to send messages to devices subscribed to topics, view the Send messages to topics
documentation.
Subscribing to topics
To subscribe a device, call the subscribeToTopic method with the topic name (must not include "/"):
import { getMessaging, subscribeToTopic } from '@react-native-firebase/messaging';
const messaging = getMessaging();
subscribeToTopic(messaging, 'weather').then(() => console.log('Subscribed to topic!'));Unsubscribing to topics
To unsubscribe from a topic, call the unsubscribeFromTopic method with the topic name:
import { getMessaging, unsubscribeFromTopic } from '@react-native-firebase/messaging';
const messaging = getMessaging();
unsubscribeFromTopic(messaging, 'weather').then(() => console.log('Unsubscribed from the topic!'));firebase.json
Messaging can be further configured to provide more control over how FCM is handled internally within your application.
Auto Registration (iOS)
React Native Firebase Messaging automatically registers the device with APNs to receive remote messages. If you need
to manually control registration you can disable this via the firebase.json file:
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_ios_auto_register_for_remote_messages": false
}
}Once auto-registration is disabled you must manually call registerDeviceForRemoteMessages in your JavaScript code as
early as possible in your application startup;
import { getMessaging, registerDeviceForRemoteMessages } from '@react-native-firebase/messaging';
async function registerAppWithFCM() {
await registerDeviceForRemoteMessages(getMessaging());
}ARM64 iOS Simulator: React Native Firebase intentionally does not call UIKit
registerForRemoteNotificationson Apple Silicon Simulator builds (registration,
auto-registration, andrequestPermission's APNs side-effect). Calling that API can block the
main thread indefinitely.registerDeviceForRemoteMessagestherefore stays pending until a
~10 second global-queue timer rejects withmessaging/registration-timeout.requestPermissionstill resolves withAuthorizationStatus(it does not reject with that
code). You will not get a real APNs device token on that simulator — use a physical iOS device
when you need end-to-end push registration. IfregisterDeviceForRemoteMessagesis called again
before a prior attempt settles, the earlier promise rejects withmessaging/registration-superseded. See
Migrating to v26 — iOS APNs registration.
Foreground Presentation Options (iOS)
React Native Firebase Messaging configures how to present a notification in a foreground app.
Refer to UNNotificationPresentationOptions for the details.
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_ios_foreground_presentation_options": ["badge", "sound", "list", "banner"]
}
}Auto initialization
Firebase generates an Instance ID, which FCM uses to generate a registration token (or, when Installation ID messaging is
enabled, to register via FID — see Migrating to Installation ID and
Installation ID messaging)
and which Analytics uses for data collection.
When an Instance ID is generated, the library will upload the identifier and configuration data to Firebase. In most cases,
you do not need to change this behavior.
If you prefer to prevent Instance ID auto-generation, disable auto initialization for FCM and Analytics:
// <projectRoot>/firebase.json
{
"react-native": {
"analytics_auto_collection_enabled": false,
"messaging_auto_init_enabled": false
}
}To re-enable initialization (e.g. once requested permission) call the setAutoInitEnabled(messaging, true) method.
Background handler timeout (Android)
On Android, a background event sent to setBackgroundMessageHandler has 60 seconds to resolve before it is automatically
canceled to free up device resources. If you wish to override this value, set the number of milliseconds in your config:
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_android_headless_task_timeout": 30000
}
}Notification Channel ID
On Android, any message which displays a Notification use a default Notification Channel
(created by FCM called "Miscellaneous"). This channel contains basic notification settings which may not be appropriate for
your application. You can change what Channel is used by updating the messaging_android_notification_channel_id property:
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_android_notification_channel_id": "high-priority"
}
}Creating and managing Channels is outside of the scope of the React Native Firebase library, however external libraries
such as Notifee can provide such functionality.
Notification Color
On Android, any messages which display a Notification do not use a color to tint the content
(such as the small icon, title etc). To provide a custom tint color, update the messaging_android_notification_color property
with a Android color resource name.
The library provides a set of predefined colors corresponding to the HTML colors for convenience, for example:
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_android_notification_color": "@color/hotpink"
}
}Note that only predefined colors can be used in firebase.json. If you want to use a custom color defined in your application resources, then you should set it in the AndroidManifest.xml instead.
<resources>
<color name="my_custom_color">#123456</color>
</resources>
<manifest xmlns:tools="http://schemas.android.com/tools">
<application>
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/my_custom_color"
tools:replace="android:resource" />
</application>
</manifest>Perf Usage Index (`docs/perf/usage/index.mdx`)
title: Performance Monitoring next: /perf/axios-integration previous: /remote-config/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the performance monitoring module
yarn add @react-native-firebase/perf
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Add the Performance Monitoring Plugin
If you're using Expo, make sure to add the
@react-native-firebase/perfconfig plugin to yourapp.jsonorapp.config.js. It handles the below installation steps for you. For instructions on how to do that, view the Expo installation section.
On Android, you need to install the Google Performance Monitoring Plugin which enables automatic
HTTPS network request monitoring.
Add the plugin to your /android/build.gradle file as a dependency:
buildscript {
dependencies {
// ...
classpath 'com.google.firebase:perf-plugin:2.0.2'
}Apply the plugin via the /android/app/build.gradle file (at the top):
apply plugin: 'com.android.application'
apply plugin: 'com.google.firebase.firebase-perf'Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: initializePerformance returns synchronously on RN. Trace, HTTP metric, and screen trace start/stop are synchronous through TurboModules, matching firebase-js-sdk.
What does it do
Performance Monitoring allows you to gain insight into key performance characteristics within your React Native application.
It provides a simple API to track custom trace and HTTP request metrics.
Review and analyze that data in the Firebase console. Performance Monitoring helps you to understand where and when the
performance of your app can be improved so that you can use that information to fix performance issues.
Performance Monitoring package automatically traces events and metrics which are sent to Firebase. For more information
on the automatic traces, please see the Firebase Performance Monitoring documentation.
The package also allows you to performance monitor custom aspects to your application like network requests & task specific
app code. All performance metrics are available on your Firebase console performance tab.
Usage
Custom tracing
Below is how you would measure the amount of time it would take to complete a specific task in your app code.
import { getPerformance, trace } from '@react-native-firebase/perf';
function customTrace() {
const perf = getPerformance();
const t = trace(perf, 'custom_trace');
t.start();
t.putAttribute('user', 'abcd');
t.putMetric('credits', 30);
t.stop();
}Custom screen traces
Record a custom screen rendering trace (slow frames / frozen frames)
import { getPerformance, startScreenTrace } from '@react-native-firebase/perf';
function screenTrace() {
try {
const screenTrace = startScreenTrace(getPerformance(), 'FooScreen');
screenTrace.stop();
} catch (e) {
// rejects if iOS or (Android == 8 || Android == 8.1)
// or if hardware acceleration is off
}
}HTTP Request Tracing
Below illustrates you would measure the latency of a HTTP request.
import { getPerformance, httpMetric } from '@react-native-firebase/perf';
async function getRequest(url) {
const metric = httpMetric(getPerformance(), url, 'GET');
metric.putAttribute('user', 'abcd');
metric.start();
const response = await fetch(url);
metric.setHttpResponseCode(response.status);
metric.setResponseContentType(response.headers.get('Content-Type'));
metric.setResponsePayloadSize(response.headers.get('Content-Length'));
metric.stop();
return response.json();
}
getRequest('https://api.com').then(json => {
console.log(json);
});firebase.json
Disable Auto-Initialization
The Performance Monitoring module will automatically start collecting data once it is installed. To disable this behavior,
set the perf_auto_collection_enabled flag to false:
// <project-root>/firebase.json
{
"react-native": {
"perf_auto_collection_enabled": false
}
}To re-enable collection (e.g. once you have the users consent), call the setPerformanceCollectionEnabled method:
import { getPerformance } from '@react-native-firebase/perf';
// ...
getPerformance().dataCollectionEnabled = true;Phone Number Verification Usage Index (`docs/phone-number-verification/usage/index.mdx`)
title: Phone Number Verification next: /vertexai/usage previous: /perf/ky-integration
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the phone-number-verification module
yarn add @react-native-firebase/phone-number-verificationAndroid only - This module is only available on Android. The Firebase Phone Number Verification SDK does not support iOS or web platforms. Calling any method on a non-Android platform will throw an error.
Platform support and New Architecture
| Platforms | Android only |
| New Architecture | Required from v26. See Migrating to v26. |
What does it do
Firebase Phone Number Verification provides carrier-level phone number verification on Android devices without requiring SMS codes. It verifies the user's phone number directly through the device's SIM card and carrier network, providing a seamless and secure verification experience.
To learn more, visit the Firebase Phone Number Verification documentation.
Key capabilities:
- Carrier-level verification: Verifies phone numbers directly with the mobile carrier, without SMS.
- Support detection: Check whether the device and carrier support phone number verification before attempting it. This does not require user consent.
- Verified phone number: Retrieve the device's verified phone number as a JWT token containing the phone number, timestamps, nonce, and claims. This will present a consent dialog to the user.
- Digital Credential API: Supports the Android Digital Credential API for custom verification flows.
Region & carrier limitations
Phone Number Verification depends on carrier cooperation. Not all carriers or regions are supported. Before relying on Phone Number Verification, always call getVerificationSupportInfo() to check support. If a SIM slot returns reason: 'INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED', that carrier does not participate in Phone Number Verification and you should fall back to another verification method (e.g. Firebase Auth SMS).
Common reasons verification may be unsupported:
| Reason | Meaning |
|---|---|
CAPABLE |
The SIM's carrier supports Phone Number Verification. |
INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED |
The carrier does not participate in Phone Number Verification. |
INCAPABLE_DUE_TO_ANDROID_VERSION |
The device's Android version is too old. |
INCAPABLE_DUE_TO_SIM_STATE |
No SIM inserted, or SIM is in an unusable state. |
CAPABILITY_STATUS_UNSPECIFIED |
The SDK could not determine the status. |
Usage
Check verification support
Before attempting verification, check if the device's SIM card(s) support phone number verification. This call does not require user consent and can be called freely:
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';
const supportInfo = await getVerificationSupportInfo();
for (const info of supportInfo) {
console.log(`SIM slot ${info.simSlot}:`);
console.log(' Supported:', info.isSupported);
console.log(' Carrier ID:', info.carrierId);
console.log(' Reason:', info.reason);
}The method returns an array with one entry per SIM slot. Each entry includes:
isSupported— whether Phone Number Verification is available for this SIM.simSlot— the SIM slot index (0-based).carrierId— the carrier identifier string.reason— aVerificationSupportStatusstring explaining why the SIM is or isn't supported.
Query a specific SIM slot
On dual-SIM devices, you can query a specific SIM slot by passing the slot index:
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';
const supportInfo = await getVerificationSupportInfo(0); // SIM slot 0Fallback when unsupported
If Phone Number Verification is not supported, fall back to an alternative verification method:
import { Platform } from 'react-native';
import {
getVerificationSupportInfo,
getVerifiedPhoneNumber,
} from '@react-native-firebase/phone-number-verification';
async function verifyPhoneNumber() {
if (Platform.OS !== 'android') {
// Use SMS-based verification on non-Android platforms
return verifySms();
}
const supportInfo = await getVerificationSupportInfo();
const supported = supportInfo.some(info => info.isSupported);
if (supported) {
try {
return await getVerifiedPhoneNumber();
} catch (error) {
// Fall back to SMS on failure
return verifySms();
}
}
// Carrier or device doesn't support Phone Number Verification
return verifySms();
}Verify a phone number
To initiate the full verification flow, call getVerifiedPhoneNumber(). This will present a consent dialog to the user asking permission to share their phone number. Your app should prepare the user for this consent screen before calling the method — for example, by explaining why their phone number is needed.
For guidance on handling user consent, see the Firebase Phone Number Verification getting started guide.
import { getVerifiedPhoneNumber } from '@react-native-firebase/phone-number-verification';
try {
const result = await getVerifiedPhoneNumber();
console.log('Phone number:', result.phoneNumber);
console.log('Token:', result.token);
console.log('Expires at:', new Date(result.expirationTimestamp * 1000));
console.log('Issued at:', new Date(result.issuedAtTimestamp * 1000));
console.log('Nonce:', result.nonce);
console.log('Claims:', result.claims);
} catch (error) {
console.error('Verification failed:', error.code, error.message);
}The returned result includes:
phoneNumber— the verified phone number in E.164 format.token— the raw JWT token string for server-side validation.expirationTimestamp— token expiration as Unix epoch seconds.issuedAtTimestamp— token issued-at time as Unix epoch seconds.nonce— the nonce from the JWT payload, ornull.claims— all JWT claims as a key-value map, ornull.
Custom verification with Digital Credentials
For advanced use cases, you can use the Digital Credential API flow:
import {
getDigitalCredentialPayload,
exchangeCredentialResponseForPhoneNumber,
} from '@react-native-firebase/phone-number-verification';
// Step 1: Get the credential payload
const payload = await getDigitalCredentialPayload('your-unique-nonce');
// Step 2: Use the payload with Android Credential Manager
// ... (pass payload to CredentialManager API)
// Step 3: Exchange the response for a verified phone number
const result = await exchangeCredentialResponseForPhoneNumber(credentialResponse);
console.log('Phone number:', result.phoneNumber);
console.log('Expires at:', new Date(result.expirationTimestamp * 1000));Error handling
All methods reject with structured error codes from the Firebase Phone Number Verification SDK. The error.code property contains one of these values:
| Error Code | Meaning |
|---|---|
pnv/carrier-not-supported |
The SIM's carrier does not support Phone Number Verification. |
pnv/invalid-digital-credential-response |
The Digital Credential API response was invalid. |
pnv/integrity-check-failed |
Device integrity check failed. |
pnv/preflight-check-failed |
Server-side preflight check failed. |
pnv/unsupported-operation |
The API call is not supported with the given parameters. |
pnv/credential-manager-error |
Android Credential Manager failed unexpectedly. |
pnv/invalid-test-number-id |
Test number IDs are empty, expired, or duplicated. |
pnv/test-session-already-enabled |
enableTestSession was called more than once. |
pnv/activity-context-required |
An Activity context is required (app may be in the background). |
import {
getVerifiedPhoneNumber,
PnvErrorCode,
type PnvError,
} from '@react-native-firebase/phone-number-verification';
try {
const result = await getVerifiedPhoneNumber();
} catch (error) {
const pnvError = error as PnvError;
switch (pnvError.code) {
case PnvErrorCode.CARRIER_NOT_SUPPORTED:
// Fall back to SMS verification
break;
case PnvErrorCode.ACTIVITY_CONTEXT_REQUIRED:
// Retry when app is in foreground
break;
default:
console.error('Phone Number Verification error:', pnvError.code, pnvError.message);
}
}Testing
To test without a real SIM card and carrier, use Firebase's test mode. This requires setup in the Firebase Console:
- Generate a test token: In the Firebase Console, navigate to Phone Number Verification and generate a test token. Test tokens have a 7-day Time-To-Live.
- Identity and Access Management permissions: Ensure the service account has the required
firebasepnv.testSessions.createpermission. - Google system services beta: On the test device, enroll the Google system services app into the beta channel via Google Play.
- Call
enableTestSessiononce: Pass the token before any verification calls. This must be called only once per app instance — calling it again will reject withpnv/test-session-already-enabled.
import {
enableTestSession,
getVerifiedPhoneNumber,
} from '@react-native-firebase/phone-number-verification';
// Call once at app startup for testing
await enableTestSession('your-test-token-from-firebase-console');
// Now verification calls return test data
// Phone numbers in test mode follow the format: valid country code + all zeros
const result = await getVerifiedPhoneNumber();
console.log('Test phone number:', result.phoneNumber);Platform handling
This module is Android-only. On non-Android platforms, all methods throw an error with the message "Firebase Phone Number Verification is only supported on Android." You can guard against this using Platform.OS:
import { Platform } from 'react-native';
import { getVerificationSupportInfo } from '@react-native-firebase/phone-number-verification';
if (Platform.OS === 'android') {
const supportInfo = await getVerificationSupportInfo();
// ...
}Remote Config Usage Index (`docs/remote-config/usage/index.mdx`)
title: Remote Config next: /perf/usage previous: /installations/usage
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
This module also requires that the @react-native-firebase/analytics module is already setup and installed. To install the "analytics" module, view it's Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the remote-config module
yarn add @react-native-firebase/remote-config
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: reset() is Android only — iOS does not clear activated, fetched, or default Remote Config values. setDefaultsFromResource loads from native .plist / XML resource files.
What does it do
Remote Config allows you to change the appearance and/or functionality of your app without requiring an app update.
Remote Config values are input into the Firebase console and accessible via a JavaScript API. This gives you full control
over when and how these Remote Config values are applied and affect your application.
Usage
To get started, you need to define some parameters over on the Firebase Console.
Each parameter is assigned a unique "key" and values. The values can be broken down to target specific conditions (such as Android or iOS). In the above example,
only Android devices would receive enabled for the awesome_new_feature parameter.
Default values
Before fetching the parameters from Firebase, it is first important to set some default values. Default values
help ensure that your application code runs as expected in scenarios where the device has not yet retrieved the values.
An example of this is having no network or you have not yet fetched them within your own code.
Setting default values helps to ensure that both the local device & Firebase servers are both in sync. Call thesetDefaults method early on in your application:
import React, { useEffect } from 'react';
import { getRemoteConfig } from '@react-native-firebase/remote-config';
function App() {
useEffect(() => {
const remoteConfig = getRemoteConfig();
remoteConfig.defaultConfig = {
awesome_new_feature: 'disabled',
};
console.log('Default values set.');
}, []);
}Fetch & Activate
Before reading the values from Firebase, we first need to pull them from Firebase (fetching) & then enable them on
the device (activating). The fetchAndActivate API combines both tasks into a single flow:
import { getRemoteConfig, fetchAndActivate } from '@react-native-firebase/remote-config';
const remoteConfig = getRemoteConfig();
remoteConfig.defaultConfig = {
awesome_new_feature: 'disabled',
};
fetchAndActivate(remoteConfig).then(fetchedRemotely => {
if (fetchedRemotely) {
console.log('Configs were retrieved from the backend and activated.');
} else {
console.log(
'No configs were fetched from the backend, and the local configs were already activated',
);
}
});Reading values
With the defaults set and the remote values fetched from Firebase, we can now use the getValue method to get the
value and use a number of methods to retrieve the value (same API as Firebase Remote Config web SDK)
import { getRemoteConfig, getValue } from '@react-native-firebase/remote-config';
const awesomeNewFeature = getValue(getRemoteConfig(), 'awesome_new_feature');
// resolves value to string
if (awesomeNewFeature.asString() === 'enabled') {
enableAwesomeNewFeature();
}
// resolves value to number
// if it is not a number or source is 'static', the value will be 0
if (awesomeNewFeature.asNumber() === 5) {
enableAwesomeNewFeature();
}
// resolves value to boolean
// if value is any of the following: '1', 'true', 't', 'yes', 'y', 'on', it will resolve to true
// if source is 'static', value will be false
if (awesomeNewFeature.asBoolean() === true) {
enableAwesomeNewFeature();
}The API also provides a getAll method to read all parameters at once rather than by key:
import { getAll, getRemoteConfig } from '@react-native-firebase/remote-config';
const parameters = getAll(getRemoteConfig());
Object.entries(parameters).forEach($ => {
const [key, entry] = $;
console.log('Key: ', key);
console.log('Source: ', entry.getSource());
console.log('Value: ', entry.asString());
});Value source
When a value is read, it contains source data about the parameter. As explained above, if a value is read before it has
been fetched & activated then the value will fallback to the default value set. If you need to validate whether the value
returned from the module was local or remote, the getSource() method can be conditionally checked:
import { getRemoteConfig, getValue } from '@react-native-firebase/remote-config';
const awesomeNewFeature = getValue(getRemoteConfig(), 'awesome_new_feature');
if (awesomeNewFeature.getSource() === 'remote') {
console.log('Parameter value was from the Firebase servers.');
} else if (awesomeNewFeature.getSource() === 'default') {
console.log('Parameter value was from a default value.');
} else {
console.log('Parameter value was from a locally cached value.');
}Caching
Although Remote Config is a data-store, it is not designed for frequent reads - Firebase heavily caches the parameters
(default is 12 hours).
You can however specify your own cache length by specifically calling the fetch method with the number of seconds to
cache the values for:
import { fetchConfig, getRemoteConfig } from '@react-native-firebase/remote-config';
// Fetch and cache for 5 minutes
const remoteConfig = getRemoteConfig();
remoteConfig.settings = { minimumFetchIntervalMillis: 300000 };
await fetchConfig(remoteConfig);To bypass caching fully, you can pass a value of 0. Be warned Firebase may start to reject your requests
if values are requested too frequently.
You can also apply a global cache frequency by calling the setConfigSettings method with the minimumFetchIntervalMillis property:
import { getRemoteConfig } from '@react-native-firebase/remote-config';
const remoteConfig = getRemoteConfig();
remoteConfig.settings = {
minimumFetchIntervalMillis: 30000,
};Real-time updates
Remote Config has the ability to trigger real-time Remote Config updates
in applications that attach one or more listeners for them.
Key points to know about real-time updates
- No activation by default: If there is a config template update and you have a listener subscribed for real time updates, the native SDK will automatically fetch the new remote config template but will not activate it for you. Your callback code is responsible for activating the new template, and your application code is responsible for getting and reacting to the new config template values
- Keys considered updated until activated: Config template keys are considered updated if they have been changed since you last activated the remote config template. If you never activate the new template, previously changed keys will continue to show up in the set of updated keys sent to your registered listener callback
- Real-time updates has a cost: If you attach a listener, the native SDK opens a persistent web socket to the firebase servers. If all listeners are unsubscribed, this web socket is closed. Consider the battery usage and network data usage implications for your users
- Unactivated changes result in immediate callback If there has been a template change since you last activated, and you attach a listener, that listener will be called immediately to update you on the pending changes
Known Issues
- Other platform requires a
fetchAndActivatebefore updates come through During testing here in react-native-firebase and the sister projectFlutterFire, we noticed that the firebase-js-sdk does not seem to send realtime update events through unless you have previously calledfetchAndActivate
Here is an example of how to use the feature, with comments emphasizing the key points to know:
import { activate, getRemoteConfig, onConfigUpdate } from '@react-native-firebase/remote-config';
// Add a config update listener where appropriate, perhaps in app startup, or a specific app area.
// Multiple listeners are supported, so listeners may be screen-specific and only handle certain keys
// depending on application requirements
let remoteConfigListenerUnsubscriber = onConfigUpdate(getRemoteConfig(), {
next: update => {
console.log('remote-config keys updated: ' + Array.from(update.getUpdatedKeys()));
// If you use realtime updates, the SDK fetches the new config for you.
// However, you must activate the new config so it is in effect
activate(getRemoteConfig());
},
error: error => {
console.log('remote-config listener subscription error: ' + error);
},
});
// unsubscribe the listener when no longer needed - remote config will close the network socket if there
// are no active listeners, potentially minimizing application user data and battery usage.
remoteConfigListenerUnsubscriber();Storage Usage Index (`docs/storage/usage/index.mdx`)
title: Cloud Storage next: /app/usage previous: /messaging/migrating-to-installation-id
Installation
This module requires that the @react-native-firebase/app module is already setup and installed. To install the "app" module, view the
Getting Started documentation.
# Install & setup the app module
yarn add @react-native-firebase/app
# Install the storage module
yarn add @react-native-firebase/storage
# If you're developing your app using iOS, run this command
cd ios/ && pod installIf you're using an older version of React Native without autolinking support, or wish to integrate into an existing project,
you can follow the manual installation steps for iOS and Android.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: putFile and writeToFile are native-only file-path APIs with no firebase-js-sdk equivalent. Use FilePath from @react-native-firebase/app for device paths.
What does it do
Storage is built for app developers who need to store and serve user-generated content, such as photos or videos.
Your data is stored in a Google Cloud Storage bucket, an exabyte scale object storage solution with high availability and
global redundancy. Storage lets you securely upload these files directly from mobile devices, handling spotty networks with ease.
Usage
Your files are stored in a Google Cloud Storage bucket. The files in this bucket are presented in a hierarchical structure,
just like a file system. By creating a reference to a file, your app gains access to it. These references can then be
used to upload or download data, get or update metadata or delete the file. A reference can either point to a specific
file or to a higher level node in the hierarchy.
The Storage module also provides support for multiple buckets.
You can view your buckets on the Firebase Console.
Creating a reference
A reference is a local pointer to some file on your bucket. This can either be a file which already exists, or one
which does not exist yet. To create a reference, use the ref method:
import { getStorage, ref } from '@react-native-firebase/storage';
const reference = ref(getStorage(), 'black-t-shirt-sm.png');You can also specify a file located in a deeply nested directory:
const reference = ref(getStorage(), '/images/t-shirts/black-t-shirt-sm.png');Upload a file
To upload a file directly from the users device, the putFile method on a reference accepts a string path to the file
on the users device. For example, you may be creating an app which uploads users photos. The React Native Firebase
library provides utilities such as FilePath to help identify device directories:
import React, { useEffect } from 'react';
import { View, Button } from 'react-native';
import { FilePath } from '@react-native-firebase/app';
import { getStorage, ref, putFile } from '@react-native-firebase/storage';
function App() {
const storage = getStorage();
const reference = ref(storage, 'black-t-shirt-sm.png');
return (
<View>
<Button
onPress={async () => {
const pathToFile = `${FilePath.PICTURES_DIRECTORY}/black-t-shirt-sm.png`;
await putFile(reference, pathToFile);
}}
/>
</View>
);
}Tasks
The putFile method returns a Task, which if required, allows you to hook into information
such as the current upload progress:
const task = putFile(reference, pathToFile);
task.on('state_changed', taskSnapshot => {
console.log(`${taskSnapshot.bytesTransferred} transferred out of ${taskSnapshot.totalBytes}`);
});
task.then(() => {
console.log('Image uploaded to the bucket!');
});A task also provides the ability to pause & resume on-going operations:
const task = putFile(reference, pathToFile);
task.pause();
// Sometime later...
task.resume();Download URLs
A common use-case for Cloud Storage is to use it as a global Content Delivery Network (CDN) for your images. When uploading
files to a bucket, they are not automatically available for consumption via a HTTP URL. To generate a new Download URL, you
need to call the getDownloadURL method on a reference:
import { getStorage, ref, getDownloadURL } from '@react-native-firebase/storage';
const url = await getDownloadURL(ref(getStorage(), 'images/profile-1.png'));Images uploaded manually via the Firebase Console automatically generate a download URL.
Listing files & directories
If you wish to view a full list of the current files & directories within a particular bucket reference, you can use
the list method. The results are however paginated, and if more results are available you can pass a page token into the request:
import { getStorage, ref } from '@react-native-firebase/storage';
function listFilesAndDirectories(reference, pageToken) {
return reference.list({ pageToken }).then(result => {
// Loop over each item
result.items.forEach(ref => {
console.log(ref.fullPath);
});
if (result.nextPageToken) {
return listFilesAndDirectories(reference, result.nextPageToken);
}
return Promise.resolve();
});
}
const reference = ref(getStorage(), 'images');
listFilesAndDirectories(reference).then(() => {
console.log('Finished listing');
});Security
By default your bucket will come with rules which allows only authenticated users on your project to access it. You can
however fully customize the security rules to your own applications requirements.
To learn more, view the Storage Security documentation
on the Firebase website.
Multiple Buckets
A single Firebase project can have multiple storage buckets. The module will use the default bucket if no bucket argument
is passed to the storage instance. To switch buckets, provide the module with the gs:// bucket URL found on the
Firebase Console, under Storage > Files.
import { getStorage } from '@react-native-firebase/storage';
import { getApp } from '@react-native-firebase/app';
const defaultStorageBucket = getStorage();
const secondaryStorageBucket = getStorage(getApp(), 'gs://my-secondary-bucket.appspot.com');Vertexai Usage Index (`docs/vertexai/usage/index.mdx`)
title: VertexAI next: /migrating-to-v6 previous: /phone-number-verification/usage
Vertex AI has been deprecated by Google in favor of the Firebase AI Logic SDK.
Using the Firebase AI Logic SDK with the Vertex AI Gemini API is still generally available (GA).
To start using the new SDK, import the @react-native-firebase/ai package and use the modular method getAI() to initialize. See details in the migration guide.
// BEFORE - using firebase/vertexai
import { initializeApp } from 'firebase/app';
import { getVertexAI, getGenerativeModel } from 'firebase/vertexai'; // Remove this
// AFTER - using firebase/ai
import { initializeApp } from 'firebase/app';
import { getAI, getGenerativeModel } from 'firebase/ai'; // Add thisPlatform support
| Platforms | Android, iOS, Web (firebase-js-sdk interop) |
| New Architecture | Not required — pure JavaScript package with no native TurboModule. |
Deprecated: Prefer
@react-native-firebase/ai— see the Firebase migration guide.
About (`docs/about.mdx`)
title: About noindex: true
About React Native Firebase
The React Native Firebase project started life in late 2016 as a personal project Mike Diarmid
and Elliot Hesp were working on. The project gained instant popularity, allowing React Native developers
to hook into the native services Firebase provides.
During the first few months of its development, the repository was moved into the organization of Invertase on GitHub.
The organization was a collection of the personal and combined Open Source efforts Mike and Elliot had been
working over the past number of years. With a constant flow of feature requests, issues and contributions,
the library rapidly grew in popularity, achieving over 100k NPM downloads in its first 12 months of development.
In mid-2017, we were approached by Google, who offered to help ensure the projects continued support by providing direct contact with the
Firebase team and by providing funding to ensure the project had dedicated time assigned to its upkeep.
In the 2018 Firebase Summit in Prague during the opening keynote, Google openly announced their
working relationship with Invertase - check it out below:
https://twitter.com/rnfirebase/status/1056839638961348608/video/1
Future of the library
The React Native Firebase library has been a huge driving force for our knowledge and experience. Even with years of
experience in Open Source, JavaScript, Android and iOS, we're constantly learning and improving the library -
whilst focusing on the needs of the community and many users of the library. Maintaining a popular Open Source
library is hard, yet rewarding work.
With the support from the community and Google, we're pleased to announce that starting in 2019, our very own
Mike Diarmid will be working full time on the library. With the lessons we've learnt, we'll be focusing on taking the
library to a new level. Read about it here.
The success and upkeep of the library would not be possible without the support and contributions from the community.
To date, we've had contributions from 114 members of the Open Source community on the repository to who we're very
grateful to, the project wouldn't be where it is without you. Special thanks to Chris Bianca
at CS Frequency Limited for their work in helping to get this project off the ground.
We'd also like to extend our thanks to our backers on Open Collective, whose contributions have made it possible to
sustain the vast amount of time required in the upkeep of such a project.
The future of Invertase and React Native Firebase is exciting.
Enabling Multidex (`docs/enabling-multidex.mdx`)
title: Enabling Multidex
As more native dependencies are added to your project, it may bump you over the
64k method limit on the Android build system. Once this limit has been reached, you will start to see the following error
whilst attempting to build your Android application:
Execution failed for task ':app:mergeDexDebug'.To learn more about multidex, view the official Android documentation.
Enabling Multidex
There are 3 steps involved in enabling multidex.
Steps 1 and 2 tell Gradle to turn on multidex with a directive, and add new dependency.
Open the /android/app/build.gradle file. Under dependencies we need to add the module, and then enable it
within the defaultConfig:
android {
defaultConfig {
// ...
multiDexEnabled true // <-- ADD THIS in the defaultConfig section
}
// ...
}
dependencies {
implementation 'androidx.multidex:multidex:2.0.1' // <-- ADD THIS DEPENDENCY
}The 3rd step is to alter your android/app/src/main/java/.../MainApplication.java file to extend MultiDexApplication like so:
// ... all your other imports here
import androidx.multidex.MultiDexApplication; // <-- ADD THIS IMPORT
// Your class definition needs `extends MultiDexApplication` like below
public class MainApplication extends MultiDexApplication implements ReactApplication {Once added, rebuild your application: npx react-native run-android.
Faqs And Tips (`docs/faqs-and-tips.mdx`)
title: FAQs and Tips next: /ai/usage previous: /ios-spm
Over the years, there’s been a lot of discussions on our GitHub and Discord. Many of them have been about common problems developers face when using our package, and some of them resulted in very good advice being given.
In order to save others time and frustration, this page has been created to document some of these common problems and good pieces of advice.
If you come across a discussion that results in great advice that can benefit many developers, or a discussion that resolves a problem that many developers encounter, please do add it here! Someone will definitely be grateful.
FAQs
Why `react-native-firebase` over `firebase-js-sdk`?
This package wraps firebase-android-sdk and firebase-ios-sdk into a Javascript API for React Native projects, so the main benefits come with the access to native code.
There are more modules in the native SDKs than the web SDK because some things only make sense in a mobile / native context ( App Distribution, Crashlytics), so you can actually do more, and some of it is important for example, monitoring quality with Crashlytics
Some of the modules that are both in the web SDK and native SDK have a great deal more functionality when they can harness native APIs, like messaging (with background delivery that can start your app if not running), like App Check where you can tie the attestation to device-level providers, Storage where you can do background downloads, Performance where you can start measurements from boot, etc.
Does it work with New Architecture / Fabric / TurboModules ?
As far as we know, yes. We test with new architecture enabled now, and many of our users are using react-native 0.76+ with new architecture enabled.
We are not aware of any problems with the react-native-firebase modules themselves. Please let us know if you see anything.
However, we are still running in the TurboModule interoperability mode as we have not directly ported to Fabric internally yet. Migration is planned in the future but may still be a while.
I need help with [anything regarding v5 or earlier of React Native Firebase]. Where could I get help with that?
React Native Firebase v5 is now deprecated and unsupported. There's been over a year's grace period provided to migrate to v6, so moving forward maintainers probably won't pay much attention to issues regarding v5. Understandably, upgrading to v6 can take some effort, but staying on v5 probably isn't a great choice for the long-term health of your project.
Lots of the breaking changes that were introduced were either due to upstream deprecations in the official SDKs, or to simply make the package more stable and more representative of how the actual SDKs work.
The longer you stay on v5, the more your project will be out of sync with the official SDKs, unfortunately. Couple that with the fact that it's no longer actively supported, and that's trouble looming over the horizon for your project.
We highly recommend taking the necessary pains to update to v6.
My CI build hangs at the "Running script '[CP-User] [RNFB] Core Configuration'" step
This may be fixed by creating a firebase.json file at the root of your project if it's not there already. If you don't want to change any of the default React Native Firebase configurations, you can leave it empty in the following way:
{
"react-native": {
}
}I have a custom Analytics parameter called 'items' and it's not showing up on the Firebase console. How come?
This happens to be a known problem with the upstream Analytics SDKs. The Firebase team doesn't have any plans to fix it soon. More information about this can be found here.
I'm receiving `InternalFirebaseAuth.FIREBASE_AUTH_API is not available on this device`. How do I fix this?
To use some Firebase services (like auth) in an emulator, you need an Android virtual device with Google Play services installed. Check this Stack Overflow post for instructions on creating a new Android virtual device with the necessary APIs installed.
I'm getting an SIGABRT error in Xcode when faking a crash on iOS. How do I fix this?
When you get an error on this line when faking a crash on iOS:
RCT_EXPORT_METHOD(crash) {
if ([RNFBCrashlyticsInitProvider isCrashlyticsCollectionEnabled]) {
assert(NO);
}
}Just disable your debugger in Xcode. 'Project name' -> 'Edit Scheme...' -> 'Run' -> deselect "Debug executable"
I have the latest SDK installed, but I can't send a test in app message from the console. How do I fix this?
Sometimes when building an in-app-message in the console, sending a test to a device is not possible, as the "Test on device" button is grayed out. This can be very annoying, but have found a "work around" that enables the button:
- Make sure to fill out all fields in the first step of the form. If that doesn't enable the button:
- Make sure to click inside every field, even if the field does not need to be updated (specially the "Text color" ones). If that doesn't enable the button:
- Change between the "Message layout" options (Card, Modal, Image only and Top banner).
Sometimes, after step 3, you have to click inside a "Text color" field, but this should enable the "Test on device" option. After that you add the device Install ID, make sure to quit the app before the actual test, and then I wait for the confirmation toast to open the app up again. As long as the ID is 100% correct, the test should work as intended.
On iOS, when the app is in quit state, the setBackgroundMessageHandler is never invoked even when I receive the notification. How can I fix this?
Note: If you use @notifee/react-native, since v7.0.0,
onNotificationOpenedAppandgetInitialNotificationwill no longer trigger as notifee will handle the event.
When the app is closed/quit, this can happen even when you are getting notifications and even when you are able to invoke the app in a headless state.
To fix this:
- You first need to send the payload with "content-available: 1" in the
apnssection of the message payload so the app gets invoked in a headless state. - On the
index.jspage, if the app is invoked in headless mode, instead of returning null, return a simple component that does nothing and renders nothing. Otherwise, return the actualAppcomponent.
To view the complete detail for this solution, please refer to this page: #5656
Tips
- Whenever you face a strange issue (or an issue that causes build errors), there are two things you should always consider.
- Build processes are costly and complex, so caching is used a lot. As a result, certain changes that you make in your app can cause cache conflicts in subsequent builds. Deal with this via
npx react-native-clean-project. This does solve a lot of problems. - Try and isolate the problem with a template React Native Firebase app. This bash script is particularly helpful in making an empty template app.
- Build processes are costly and complex, so caching is used a lot. As a result, certain changes that you make in your app can cause cache conflicts in subsequent builds. Deal with this via
- Advice on supporting multiple environments (for example, dev, prod, maybe also staging, qa) for your React Native Firebase App: #3504
- Using Fastlane for iOS deployment together with RN Firebase Crashlytics within CI has been observed to cause builds that hang indefinitely. Using
setup_ci(force: true)before building the application may solve the issue.: #3706 - Be careful if you are using a VPN, Google blocks many VPN IPs causing "unavailable" errors for various firebase API calls, and on an Android emulator it might completely mess up the network adapter causing network calls to never return, not only on firebase but on the entire emulated phone.
Install Android (`docs/install-android.mdx`)
title: Android Installation
Android Manual Installation
The following steps are only required if you are using React Native 0.59 or earlier and need to manually integrate the library.
1. Update Gradle Settings
Add the following to your projects /android/settings.gradle file:
include ':@react-native-firebase_app'
project(':@react-native-firebase_app').projectDir = new File(rootProject.projectDir, './../node_modules/@react-native-firebase/app/android')2. Update Gradle Dependencies
Add the React Native Firebase module dependency to your /android/app/build.gradle file:
dependencies {
// ...
implementation project(path: ":@react-native-firebase_app")
}3. Add package to the Android Application
Import and apply the React Native Firebase module package to your /android/app/src/main/java/**/MainApplication.java file:
Import the package:
import io.invertase.firebase.app.ReactNativeFirebaseAppPackage;Add the package to the registry:
protected List<ReactPackage> getPackages() {
return Arrays.asList(
new MainReactPackage(),
new ReactNativeFirebaseAppPackage(),4. Rebuild the project
Once the above steps have been completed, rebuild your Android project:
npx react-native run-androidInstall Ios (`docs/install-ios.mdx`)
title: iOS Installation
iOS Manual Installation
The following steps are only required if you are using React Native 0.59 or earlier, and need to manually integrate the library.
1. Add the Pod
Add the RNFBApp Pod to your projects /ios/Podfile:
target 'app' do
# ...
pod 'RNFBApp', :path => '../node_modules/@react-native-firebase/app'
end2. Update Pods & rebuild the project
You may need to update your local Pods in order for the RNFBApp Pod to be installed in your project:
$ cd ios/
$ pod install --repo-updateOnce the Pods have installed locally, rebuild your iOS project:
npx react-native run-iosIos Spm (`docs/ios-spm.mdx`)
title: iOS SPM Support next: /faqs-and-tips previous: /platforms
iOS SPM Support
React Native Firebase resolves its Firebase Apple SDK dependencies with
Swift Package Manager (SPM).
This changes only how the native Firebase SDK is installed; your JavaScript and
native application code do not change.
Firebase Apple SDK 13.0.0 and later are no longer distributed through
CocoaPods. The last CocoaPods release is 12.19.0. See Google's
CocoaPods deprecation guide.
Requirements and defaults
- React Native 0.75 or newer is required (
spm_dependency). - SPM is the only supported Firebase install path for this major.
$RNFirebaseDisableSPM = trueand Expoios.disableSPM: truefailpod install/ prebuild — they do not install CocoaPods Firebase 13 pods.- SPM requires CocoaPods 1.10 or newer for the React Native pod integration.
React Native 0.75+ templates already satisfy this requirement. - SPM pins the Firebase iOS SDK to the exact version in
sdkVersions.ios.firebasein@react-native-firebase/app(currently 13.0.0).
SPM requires dynamic framework linkage:
use_frameworks! :linkage => :dynamicDo not use RNFB's SPM mode with use_frameworks! :linkage => :static.
A Podfile with no use_frameworks! line (or use_frameworks! false) is static
linkage too — that is the stock React Native / bare Expo default.
firebase-ios-sdk SPM products are automatic libraries (plain .library(...),
not type: .dynamic), so each pod that depends on them embeds its own copy.
With static pod linkage those copies collide at link time as duplicate-symbol
errors. pod install fails fast for that combination instead of surfacing the
linker failure later. Dynamic linkage is required for SPM mode to build and
run; see Sharing FirebaseCore with other native pods
for what dynamic linkage does and does not give you.
Google Sign-In caveat
Firebase Apple SDK 13 depends on App Check 12. GoogleSignIn and
Firebase 13 in the same app can fail App Check resolution until GoogleSignIn
(and any React Native wrapper that pins it) allow App Check 12. The SPM and
CocoaPods paths are separate:
- SPM: Tagged GoogleSignIn 10.0.0 still declares App Check
from: "11.0.0"(11.x). google/GoogleSignIn-iOS #626
(merged on main) widens the SPM App Check range to11.0.0 ..< 13.0.0. That change is not in a tagged release yet. An
SPM resolve can succeed only after a GoogleSignIn tag that includes #626
(or an equivalent App Check 12-capable SPM range). - CocoaPods: The GoogleSignIn podspec on main and in 10.0.0 still
declaresAppCheckCore ~> 11.0. #626 did not change the CocoaPods
dependency. CocoaPods graphs that pull GoogleSignIn alongside Firebase 13
stay blocked until a podspec bump allows App Check 12 and@react-native-google-signin/google-signin(or your Podfile pin) picks up
that release.
Track GoogleSignIn-iOS releases and the React Native Google Sign-In package
for both paths. SPM progress alone does not unblock CocoaPods consumers.
Expo projects
Expo projects must select dynamic linkage withexpo-build-properties:
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "dynamic"
}
}
]
]
}
}Do not pass disableSPM: true to the @react-native-firebase/app config
plugin — Firebase 13+ is SPM-only and that option fails prebuild.
The sections below describe editing ios/Podfile directly for React Native
CLI projects. Do not follow Podfile edits in an Expo project -- Expo
regenerates ios/Podfile from your config plugins on every prebuild. Useexpo-build-properties instead, as shown above.
Use SPM (React Native CLI)
For React Native 0.75 or newer, SPM is selected automatically. Configure dynamic
linkage in your ios/Podfile, then install pods normally:
use_frameworks! :linkage => :dynamiccd ios
pod installThe install output identifies the selected mode:
[react-native-firebase] RNFBApp: Using SPM for Firebase dependency resolution (products: FirebaseCore, FirebaseInstallations)RNFB also adds an [RNFB] Embed Firebase SPM Frameworks build phase to the app
target. This phase embeds Firebase frameworks built by SPM that React Native's
pod-level SPM integration does not otherwise copy into the app bundle.
Release build and module-resolution settings
RNFB automatically applies two build settings needed for SPM + dynamic
linkage, on every pod install/pod update:
-ObjCin the app target's linker flags and on RNFB pod targets, so
Release's dead-code stripping does not drop Firebase'sFIRLibrary/FIRComponentregistration or Measurement Objective-C
categories statically absorbed intoRNFBAnalytics.SWIFT_ENABLE_EXPLICIT_MODULES = 'NO'andCLANG_ENABLE_EXPLICIT_MODULES = 'NO'on both the app project and the Pods project, so Xcode 26's explicit
Swift and Clang modules don't fail to resolve Firebase's internal-only SPM
targets (FirebaseCoreInternal,FirebaseSharedSwift) or@imports of
Firebase modules in your own Objective-C/Objective-C++ files. This does not
disable SPM -- it makes Swift and Clang use implicit module discovery
across the app, CocoaPods, and SPM build boundary.
You do not need to configure either of these yourself. If pod install warns
that they could not be applied automatically, or if Xcode still reports that a
Firebase module cannot be resolved, add the fallback in your existingpost_install block, after react_native_post_install:
post_install do |installer|
react_native_post_install(
installer,
config[:reactNativePath],
# your existing options
)
rnfirebase_apply_spm_build_settings(installer)
endFramework-embedding fallback
RNFB normally installs its SPM framework-embedding phase automatically after
CocoaPods has integrated [CP] Embed Pods Frameworks into the app target
(post_integrate). If pod install warns that automatic embedding could not
be configured, call the documented fallback from post_integrate:
post_integrate do |installer|
rnfirebase_add_spm_embed_phase(installer)
endDo not add the fallback unless the warning appears or the generated app target
does not contain [RNFB] Embed Firebase SPM Frameworks.
Sharing FirebaseCore with other native pods
React Native attaches SPM products to each pod target via spm_dependency.
Because firebase-ios-sdk products are automatic libraries, each dynamic pod
framework that depends on Firebase embeds its own copy of FirebaseCore.FirebaseApp.configure() in the app configures only the copy that target
links. Another pod's copy is never configured, so FirebaseApp.app() can
return nil there (and Auth can silently look signed-out even when RNFB JS
Auth has a user).
| RNFB | Other native dependency | Shared FirebaseCore? |
|---|---|---|
| SPM | SPM (spm_dependency) |
No: each dynamic pod embeds its own copy |
| SPM | CocoaPods Firebase pods | No: dual resolution |
CocoaPods Firebase is no longer available for Firebase 13+. If a third-party
native module must share one configured FirebaseApp with RNFB, that module
must also resolve Firebase via SPM (same exact SDK version), not CocoaPods
trunk. Do not mix RNFB SPM with a third-party pod that still pulls Firebase
via CocoaPods — that is dual resolution and does not produce one shared
runtime.
Static pod linkage is not a sharing workaround under SPM: it fails at link
time with duplicate symbols (and pod install rejects the combination).
Troubleshooting
pod installfails with "Firebase Apple SDK is no longer distributed through CocoaPods":
Remove$RNFirebaseDisableSPM = trueand Expoios.disableSPM. Useuse_frameworks! :linkage => :dynamicand React Native 0.75+.pod installfails with "SPM + static linkage is not supported": Use
dynamic linkage (use_frameworks! :linkage => :dynamic). A Podfile with nouse_frameworks!line (oruse_frameworks! false), the stock React Native /
Expo default, is static linkage too.- With the stock template Podfile,
USE_FRAMEWORKS=dynamic pod installalso
works, but it must be set for everypod install(including CI); the
Podfile line is the durable fix. - Expo: set
ios.useFrameworksto"dynamic"in theexpo-build-properties
plugin (see Expo projects), then re-runnpx expo prebuild. Only if you maintainios/by hand (no prebuild), set"ios.useFrameworks": "dynamic"inios/Podfile.properties.jsoninstead.
- With the stock template Podfile,
FirebaseApp.app()isnil/ Auth looks signed-out inside another native
pod, or runtime logs duplicateFIRAppclasses: SPM mode cannot share oneFirebaseCoreacross dynamic pod frameworks. See
Sharing FirebaseCore with other native pods.- Google Sign-In / App Check SPM resolve failures: See
Google Sign-In caveat. FirebaseCoreInternal/FirebaseSharedSwiftcannot be resolved, or a
Release/Archive build crashes at launch with a missing Firebase symbol:
RNFB applies-ObjC,SWIFT_ENABLE_EXPLICIT_MODULES = 'NO', andCLANG_ENABLE_EXPLICIT_MODULES = 'NO'automatically; callrnfirebase_apply_spm_build_settings(installer)as a fallback only ifpod installwarns it could not do so.- A Firebase framework is missing at app launch: Re-run
pod install, check
for its automatic-embedding warning, and confirm the app target contains[RNFB] Embed Firebase SPM Frameworks. Use the fallback only when needed. spm_dependencyis unavailable: Upgrade to React Native 0.75 or newer.- SPM and CocoaPods both produce the same Firebase framework: Remove manually
declared Firebase pods/packages so RNFB owns Firebase dependency resolution. - Release archive fails with an
xcframework-ios.signature"couldn't be
copied ... because an item with the same name already exists" error: a
long-standing Xcode Archive bug with SPM binary xcframeworks, not an RNFB
regression. RNFB works around it automatically; if the warning says it could
not do so, add a Run Script build phase to your app target that removes the
colliding.signaturefile named in the error.
Migrating To V22 (`docs/migrating-to-v22.mdx`)
title: Migrating to v22 previous: / next: /migrating-to-v23
Switching off warning logs
You may notice a lot of console warning logs as we deprecate the existing namespaced API. If you would like to switch these logs off, you may set the following global property to true anywhere before you initialize Firebase.
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = true;Enabling deprecation strict modes
You may enable a feature for the API migration which will throw a javascript error immediately when any namespaced API usage is detected.
This is useful to help you quickly locate any remaining usage of the deprecated namespace API via examination of the line numbers in the stack trace.
Note that there may be modular API implementation errors within the react-native-firebase modules, this may still be useful as a troubleshooting aid when collaborating with the maintainers to correct these errors.
globalThis.RNFB_MODULAR_DEPRECATION_STRICT_MODE = true;Migrating to React Native modular API
If you are familiar with the Firebase JS SDK, the upgrade will be a familiar process, following similar steps to the migration guide for firebase-js-sdk.
React Native Firebase uses the same API as the official Firebase JS SDK modular API documentation so the same migration steps apply here, except there is no need for special "compat" imports as an intermediate step.
The process will always follow the same steps for every API you use:
- determine the new modular API function for the old namespaced API you are using
- import that new modular API function
- change the call from using the firebase module to access the API and passing parameters, to the new style of using the modular API function, passing in the firebase module object(s) required for it to work and then the parameters.
In the end, it should be a very mechanical process and can be done incrementally, one API call at a time.
There are concrete examples below to show the process
Firestore Deprecation Example
Namespaced (deprecated) Query
You ought to move away from the following way of making Firestore queries. The React Native Firebase namespaced API is being completely removed in React Native Firebase v22:
import firestore from '@react-native-firebase/firestore';
const db = firestore();
const querySnapshot = await db.collection('cities').where('capital', '==', true).get();
querySnapshot.forEach(doc => {
console.log(doc.id, ' => ', doc.data());
});Modular Query
This is how the same query would look using the new, React Native Firebase modular API:
import { collection, query, where, getDocs, getFirestore } from '@react-native-firebase/firestore';
const db = getFirestore();
const q = query(collection(db, 'cities'), where('capital', '==', true));
const querySnapshot = await getDocs(q);
querySnapshot.forEach(doc => {
console.log(doc.id, ' => ', doc.data());
});For more examples of requesting Firestore data, see the official Firebase documentation for Get data with Cloud Firestore.
Migration Help
You will find code snippets for "Web namespaced API" and "Web modular API" throughout the official Firebase documentation. Update your code to use "Web modular API". Here are some links to help you get started:
- Firestore
- Auth
- RTDB
- Storage
- Remote Config
- Messaging
- Functions
- App Check
- Analytics
- Perf
- Crashlytics (Crashlytics doesn't exist on Firebase web, this is a link to the type declarations which contains all methods available).
Migrating To V23 (`docs/migrating-to-v23.mdx`)
title: Migrating to v23 previous: /migrating-to-v22 next: /migrating-to-v24
Firebase Crashlytics
Modular API method isCrashlyticsCollectionEnabled(crashlytics) has been removed, please use the property on Crashlytics instancegetCrashlytics().isCrashlyticsCollectionEnabled instead.
Firebase Auth
MultiFactorUser.enrolledFactor has been removed, please use MultiFactorUser.enrolledFactors. See example:
const credential = await signInWithEmailAndPassword(getAuth(), '[email protected]', 'password');
const multiFactorUser = credential.user.multiFactor;
// Use below - remove any instances of `multiFactorUser.enrolledFactor`
console.log(multiFactorUser.enrolledFactors);Firebase App
gaMeasurementIdproperty fromFirebaseOptionshas been replaced withmeasurementIdto match Firebase web JS SDK.
Firebase Dynamic Links
⚠️ REMOVED ⚠️
Firebase Dynamic Links has been Removed
This package has been deprecated and removed from the React Native Firebase repository.
Why was it deprecated?
Firebase Dynamic Links has been deprecated by Google and will be shut down on August 25th, 2025. For more information about the deprecation and migration options, please visit:
Firebase Dynamic Links Deprecation FAQ
Migration Options
The deprecation FAQ provides detailed guidance on how to migrate from Firebase Dynamic Links, including:
- Full feature parity: Use alternative deep-linking service providers
- Simple deep-linking: Migrate to App Links and Universal Links. See Firebase documentation.
- No replacement needed: Remove the package entirely
Timeline
- August 25th, 2025: Firebase Dynamic Links service will be completely shut down
- All existing links will stop working
- All APIs will return error responses
Please refer to the official deprecation FAQ for complete migration guidance and support.
Android Platform
- Android
minSdkhas been bumped from21to23(except Auth which already had aminSdkof23). - Auth play services has been bumped from
21.3.0to21.4.0. - Crashlytics gradle plugin has been bumped from
3.0.4to3.0.5. - Performance gradle plugin has been bumped from
1.4.2to2.0.0. - App distribution gradle plugin has been bumped from
5.1.0to5.1.1.
iOS platform
- Minimum iOS deployment target has now been bumped to
15from13. - Minimum Xcode version required for iOS development is now Xcode
16.2, previous was Xcode15.2. gaMeasurementIdproperty fromFirebaseOptions(nowmeasurementIdin React Native Firebase) has been removed from firebase-ios-sdk as it wasn't used.
Web platform
- Firebase JS SDK has been bumped to
12.0.0which now requires a minimum of Node.js20and a minimum ofES2020.
See release notes.
Migrating To V24 (`docs/migrating-to-v24.mdx`)
title: Migrating to v24 previous: /migrating-to-v23 next: /migrating-to-v25
Version 24 includes breaking changes for Firestore TypeScript types and Cloud Functions native integration. Review the sections below for the modules you use.
Firestore
Version 24 introduces withConverter functionality from Firebase JS SDK. Due to the differences in types between references and queries in namespace vs modular API, and the namespaced APIs deprecation cycle being effectively complete with the API set for removal, we have adopted the modular API typing in general for firestore APIs.
Reference and query types have been updated to support input of two generic types (AppModelType, DbModelType).
Additionally, to match the JS SDK, they are now exported separately at the root, instead of through FirebaseFirestoreTypes.
Most commonly these types will be affected: CollectionReference, DocumentReference, DocumentSnapshot, QueryDocumentSnapshot, QuerySnapshot, Query.
// Previously
import { doc, getFirestore, onSnapshot, FirebaseFirestoreTypes } from '@react-native-firebase/firestore';
onSnapshot(doc(getFirestore(), 'foo', 'foo'), {
next: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot) => {
console.log(snapshot.get('foo'));
},
});// Now
import { doc, getFirestore, onSnapshot, DocumentSnapshot } from '@react-native-firebase/firestore';
onSnapshot(doc(getFirestore(), 'foo', 'foo'), {
next: (snapshot: DocumentSnapshot) => {
console.log(snapshot.get('foo'));
},
});Cloud Functions
PR: #8603 / v24.0.0 (#8799 streaming callables)
From v24 onward, @react-native-firebase/functions is implemented as a TurboModule and requires React Native's New Architecture. The legacy bridge module was removed.
Who is affected
| You use… | Action |
|---|---|
@react-native-firebase/functions on New Architecture |
No change required |
@react-native-firebase/functions on the legacy architecture |
Enable New Architecture, or stay on v23 if you cannot migrate yet |
| Other RN Firebase modules only | Functions is the first module with a hard requirement; @react-native-firebase/app prints a deprecation warning on legacy architecture builds |
Enable New Architecture
React Native CLI (Android) — set in android/gradle.properties:
newArchEnabled=trueReact Native CLI (iOS) — New Architecture is enabled when RCT_NEW_ARCH_ENABLED=1 during pod install (React Native sets this from newArchEnabled on recent templates). Follow the React Native New Architecture guide for your RN version.
Expo — enable in your app config (Expo SDK 52+):
{
"expo": {
"newArchEnabled": true
}
}Rebuild native projects after changing this (pod install, clean Android build).
If New Architecture is disabled
- Android: the Functions Gradle script fails the build with
New Architecture support is required for @react-native-firebase/functions. - iOS:
pod installfails withRNFBFunctions requires New Architecture. Enable New Architecture to use this module.
API notes
The JavaScript API (functions(), httpsCallable, modular helpers) is unchanged. v24 also adds httpsCallable().stream() support, which relies on the TurboModule implementation.
Other React Native Firebase modules still run on legacy architecture in v24, but old architecture support is deprecated project-wide and will be required for additional modules in future releases.
Migrating To V25 (`docs/migrating-to-v25.mdx`)
title: Migrating to v25 previous: /migrating-to-v24 next: /migrating-to-v26
Version 25 completes the TypeScript alignment started in v24. Modular types across multiple packages now match the firebase-js-sdk modular API as closely as possible. Runtime behavior is largely unchanged; TypeScript consumers and apps using the modular API are most affected.
If you upgraded to v24 for Firestore only, see Migrating to v24 first — Firestore breaking changes remain in v24.
Table of contents
- Why we made these changes
- Agent-assisted migration
- Who is affected
- General pattern
- Tooling & native SDKs
- Cloud Storage
- Realtime Database
- Remote Config
- Performance Monitoring
- Installations
- App Check
- Firebase Auth
- Cloud Messaging
- Automated migration checklist
Why we made these changes
React Native Firebase aims to be a drop-in replacement for the firebase-js-sdk — with native extensions and performance where the platform allows. At the JavaScript level we have always tracked the modular API closely, but our TypeScript declarations had diverged: namespaces specific to React Native Firebase, instance-style typings, and helper names that did not match the SDK.
v25 finishes aligning those types module by module. For you as a developer that means:
- Shared mental model — code, examples, and AI assistance written for firebase-js-sdk modular APIs map directly to React Native Firebase.
- Safer refactors — TypeScript catches incorrect imports and call shapes at compile time instead of at runtime.
- Easier cross-platform work — the same typed modular surface works across web, React Native, and shared business logic.
- A clear path forward — namespaced APIs remain for compatibility but modular root exports are the supported, typed source of truth.
Most apps behave the same after updating package versions; the work is primarily import and type adjustments where TypeScript reports errors.
Agent-assisted migration
This guide is written to be complete enough for an automated first pass. We recommend feeding this document to your coding agent, then asking it to analyze your codebase against each relevant section below and produce a concrete change list (or PR) for the packages you use. The Automated migration checklist at the end is structured for that workflow.
Who is affected
| You use… | Likely impact |
|---|---|
TypeScript + modular imports (getX(), ref(), etc.) |
High — update imports and call patterns per package sections below |
TypeScript + namespaced API only (firebase.storage().ref()) |
Low–medium — namespaced APIs remain; some types are deprecated or stricter |
| JavaScript only, no type checking | Low — runtime is mostly compatible; deprecated APIs still work but emit warnings |
General pattern
Across v25 package migrations:
- Import modular types and functions from the package root, not from
Firebase*Typesnamespaces. - Prefer free functions (
getToken(appCheck),trace(perf, name)) over instance methods on service objects. Firebase*Typesnamespaces remain for namespaced compatibility but are deprecated for new code.- Namespaced APIs (
firebase.auth(),storage()) still work; modular is the typed source of truth.
Tooling & native SDKs
Commit: c8c1fc105 (SDK bump)
| Change | Who | Action |
|---|---|---|
firebase-ios-sdk 12.12.0+ requires Xcode 26.2+ |
iOS developers | Upgrade Xcode before building v25 |
firebase-android-sdk 34.12.0, firebase-js-sdk 12.12.0 |
All | Update lockfiles / pods as usual on upgrade |
Cloud Storage
PR: #8824
Modular Storage types now match firebase-js-sdk. The namespaced API (firebase.storage(), FirebaseStorageTypes) is preserved separately and deprecated for new code.
Type & export changes
| Before (v24 modular / types) | Now (v25) |
|---|---|
Instance methods on Storage / StorageReference in modular typings |
Use root-level functions: ref(), uploadBytes(), getDownloadURL(), etc. |
refFromURL(storage, url) |
ref(storage, url) — ref() accepts gs:// and https:// URLs |
child(ref, path) |
ref(ref, path) |
Modular toString(ref) helper |
ref.toString() on the reference |
storage.statics.StringFormat, TaskEvent, TaskState |
Import StringFormat, TaskEvent, TaskState from package root |
md5hash in metadata |
md5Hash (firebase-js-sdk spelling) |
Generic Error in task callbacks |
NativeFirebaseError |
ListOptions.pageToken required string |
string | null (nullable, matching firebase-js-sdk) |
Example: modular references and uploads
// Previously
import { getStorage, refFromURL, child } from '@react-native-firebase/storage';
const storage = getStorage();
const fileRef = child(refFromURL(storage, 'gs://bucket/path/file.jpg'), 'thumb.jpg');
await fileRef.putFile(localPath);// Now
import { getStorage, ref, putFile } from '@react-native-firebase/storage';
const storage = getStorage();
const fileRef = ref(ref(storage, 'gs://bucket/path/file.jpg'), 'thumb.jpg');
await putFile(fileRef, localPath);Example: types and task constants
// Previously
import { getStorage, FirebaseStorageTypes } from '@react-native-firebase/storage';
function onState(snapshot: FirebaseStorageTypes.TaskSnapshot) {
if (snapshot.state === getStorage().app.storage().constructor.TaskState.RUNNING) { /* … */ }
}// Now
import { getStorage, ref, uploadBytesResumable, TaskState, type TaskSnapshot } from '@react-native-firebase/storage';
function onState(snapshot: TaskSnapshot) {
if (snapshot.state === TaskState.RUNNING) { /* … */ }
}RN-only helpers (putFile, writeToFile) remain exported from the package root for native file paths.
Realtime Database
PR: #8977
Modular RTDB types (DatabaseReference, Query, DataSnapshot, OnDisconnect, QueryConstraint) no longer expose namespaced instance-style methods in public typings. Use function-based modular helpers.
Breaking changes
| Before | Now |
|---|---|
import { ServerValue } from '@react-native-firebase/database' |
Use serverTimestamp() and increment(delta) |
await goOffline(db) / .then() on goOffline |
goOffline(db) returns void |
await goOnline(db) |
goOnline(db) returns void |
getServerTime(db) treated as async |
Returns synchronous Date |
Example: server timestamps
// Previously
import { getDatabase, ref, set, ServerValue } from '@react-native-firebase/database';
await set(ref(getDatabase(), 'posts/1'), { createdAt: ServerValue.TIMESTAMP });// Now
import { getDatabase, ref, set, serverTimestamp } from '@react-native-firebase/database';
await set(ref(getDatabase(), 'posts/1'), { createdAt: serverTimestamp() });Example: modular query helpers
// Previously — instance methods typed on modular references
import {
getDatabase,
ref,
query,
orderByChild,
equalTo,
onValue,
} from '@react-native-firebase/database';
const db = getDatabase();
const scoresRef = ref(db, 'scores');
const q = query(scoresRef, orderByChild('score'), equalTo(100));
onValue(q, snapshot => {
/* … */
});Function-based helpers (query, orderByChild, onValue, etc.) are unchanged at runtime; TypeScript may now require you to stop calling deprecated instance methods (.orderByChild(), .on()) on modular-typed references and use the modular functions instead.
Namespaced firebase.database.ServerValue remains available.
Remote Config
PR: #8972
Modular Remote Config now uses firebase-js-sdk type names and instance properties.
Removed / renamed modular API
| Removed (v24) | Replacement (v25) |
|---|---|
fetch(remoteConfig, expirationDurationSeconds?) |
fetchConfig(remoteConfig) |
setConfigSettings(remoteConfig, settings) |
remoteConfig.settings = { minimumFetchIntervalMillis, fetchTimeoutMillis } |
setDefaults(remoteConfig, defaults) |
remoteConfig.defaultConfig = { … } |
onConfigUpdated(remoteConfig, cb) |
onConfigUpdate(remoteConfig, observer) |
fetchTimeMillis(), settings(), lastFetchStatus() helpers |
Read remoteConfig.fetchTimeMillis, .settings, .lastFetchStatus |
RemoteConfigValue.value / .source getters |
value.asString() (etc.) and value.getSource() |
Exports: LastFetchStatus, ValueSource, ConfigSettings, ConfigDefaults, ConfigValue, ConfigValues, LastFetchStatusType, RemoteConfigLogLevel |
Use FetchStatus, ValueSource, Value, RemoteConfigSettings, LogLevel |
Settings field rename: modular RemoteConfigSettings uses fetchTimeoutMillis (firebase-js-sdk), not the older React Native Firebase style fetchTimeMillis on the modular surface.
Example: fetch and read values
// Previously
import {
getRemoteConfig,
fetch,
activate,
getValue,
FirebaseRemoteConfigTypes,
} from '@react-native-firebase/remote-config';
const rc = getRemoteConfig();
await fetch(rc, 3600);
await activate(rc);
const flag = getValue(rc, 'feature_enabled');
console.log(flag.value, flag.source);// Now
import {
getRemoteConfig,
fetchConfig,
activate,
getValue,
type Value,
} from '@react-native-firebase/remote-config';
const rc = getRemoteConfig();
rc.settings = {
minimumFetchIntervalMillis: 3600000,
fetchTimeoutMillis: 60000,
};
await fetchConfig(rc);
await activate(rc);
const flag: Value = getValue(rc, 'feature_enabled');
console.log(flag.asString(), flag.getSource());Performance Monitoring
PR: 4aedfe883 (TypeScript migration)
Breaking changes
| Before | Now |
|---|---|
await initializePerformance(app, settings) |
Returns FirebasePerformance synchronously |
perf.newTrace(name), perf.startTrace(name) |
trace(perf, name) |
perf.newHttpMetric(url, method) |
httpMetric(perf, url, method) |
perf.newScreenTrace(name) / startScreenTrace(name) |
newScreenTrace(perf, name) / startScreenTrace(perf, name) |
perf.setPerformanceCollectionEnabled(bool) |
perf.dataCollectionEnabled = bool |
PerformanceSettings React Native Firebase shape |
{ dataCollectionEnabled?, instrumentationEnabled? } (firebase-js-sdk) |
trace.getAttribute(key) typed as string | null |
string | undefined |
RN-only exports retained: httpMetric, newScreenTrace, startScreenTrace, HttpMethod, HttpMetric, ScreenTrace.
Example
// Previously
import { getPerformance } from '@react-native-firebase/perf';
const perf = getPerformance();
const t = perf.newTrace('load_screen');
await t.start();// Now
import { getPerformance, trace } from '@react-native-firebase/perf';
const perf = getPerformance();
const t = trace(perf, 'load_screen');
await t.start();Installations
PR: 739a4ca36 (TypeScript migration)
Modular getInstallations() returns a firebase-js-sdk-shaped Installations object exposing only app. Use modular helper functions instead of instance methods.
Breaking changes
| Before | Now |
|---|---|
installations.getId() |
getId(installations) |
installations.getToken() |
getToken(installations) |
installations.delete() |
deleteInstallations(installations) — argument is required |
Example
// Previously
import { getInstallations } from '@react-native-firebase/installations';
const installations = getInstallations();
const id = await installations.getId();// Now
import { getInstallations, getId } from '@react-native-firebase/installations';
const installations = getInstallations();
const id = await getId(installations);Namespaced firebase.installations() / FirebaseInstallationsTypes remain available (deprecated).
App Check
PR: #8889
Version 25 aligns App Check's modular exports more closely with the Firebase JS SDK. If your app uses the modular API, import App Check types and helpers directly from @react-native-firebase/app-check instead of routing modular code through FirebaseAppCheckTypes.
The most common updates are:
- Import modular helpers such as
initializeAppCheck,getToken,getLimitedUseToken,setTokenAutoRefreshEnabled, andonTokenChangedfrom the package root. - Import modular types such as
AppCheckandAppCheckTokenResultfrom the package root. FirebaseAppis no longer exported from@react-native-firebase/app-check; import it from@react-native-firebase/app.FirebaseAppCheckTypesis type-only — useimport type { FirebaseAppCheckTypes }.- Modular
AppCheckhas no instance methods (matching firebase-js-sdk); use free functions. onTokenChangedcallback receivesAppCheckTokenResult, notAppCheckListenerResult.- Keep using
ReactNativeFirebaseAppCheckProvideron React Native when you need native provider selection for Android / Apple / web.
// Previously
import appCheck, { FirebaseAppCheckTypes } from '@react-native-firebase/app-check';
const instance = appCheck();
instance.getToken().then((result: FirebaseAppCheckTypes.AppCheckTokenResult) => {
console.log(result.token);
});// Now
import { getApp } from '@react-native-firebase/app';
import {
AppCheckTokenResult,
ReactNativeFirebaseAppCheckProvider,
initializeAppCheck,
getToken,
} from '@react-native-firebase/app-check';
const provider = new ReactNativeFirebaseAppCheckProvider();
provider.configure({
android: {
provider: __DEV__ ? 'debug' : 'playIntegrity',
},
apple: {
provider: __DEV__ ? 'debug' : 'appAttestWithDeviceCheckFallback',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'your-recaptcha-site-key',
},
});
const appCheck = await initializeAppCheck(getApp(), {
provider,
isTokenAutoRefreshEnabled: true,
});
const result: AppCheckTokenResult = await getToken(appCheck);
console.log(result.token);If you do not need to reuse a provider instance, you can now also pass the React Native provider configuration inline through providerOptions:
import { getApp } from '@react-native-firebase/app';
import { initializeAppCheck } from '@react-native-firebase/app-check';
await initializeAppCheck(getApp(), {
provider: {
providerOptions: {
android: {
provider: __DEV__ ? 'debug' : 'playIntegrity',
},
apple: {
provider: __DEV__ ? 'debug' : 'appAttestWithDeviceCheckFallback',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'your-recaptcha-site-key',
},
},
},
isTokenAutoRefreshEnabled: true,
});Firebase Auth
PR: #8991
Version 25 aligns @react-native-firebase/auth TypeScript types with the firebase-js-sdk modular API. Runtime behavior is largely unchanged, but TypeScript consumers should review the following breaking changes.
For maintainers and coding agents: the living triage matrix is okf-bundle/packages/auth/compare-types-triage.md. Run yarn compare:types auth after public API edits and update .github/scripts/compare-types/configs/auth.ts when differences are intentional.
Platform matrix (read before changing Auth)
| Context | Platform.OS |
Backend | Notes |
|---|---|---|---|
| iOS/Android | ios, android |
Native Firebase Auth SDK | Native bridge types (verifyPhoneNumber listener, Multi-Factor Authentication overloads, async isSignInWithEmailLink) |
| Other/Hermes | e.g. macOS, Windows RN | firebase-js-sdk via the auth web bridge | No DOM; MFA/TOTP covered by tests/local-tests |
| Other/Web | browser embedding | firebase-js-sdk | DOM APIs (reCAPTCHA, redirect) possible but not all delegated yet |
When a symbol is documented as iOS/Android only, do not assume it throws or is missing on Other without checking the web bridge. When compare:types signatures match but runtime differs, document in triage / this guide (not necessarily in differentShape).
Modular types
Import modular types directly from @react-native-firebase/auth instead of FirebaseAuthTypes where possible. The namespaced FirebaseAuthTypes namespace remains available but is deprecated.
For auth errors, use NativeFirebaseAuthError (or the modular AuthError interface) instead of expecting a firebase-js-sdk AuthError class export — React Native Firebase does not re-export the firebase-js-sdk error class.
Removed modular export
initializeRecaptchaConfigis not exported. React Native Firebase uses native SDK Phone Auth verification rather than the browser reCAPTCHA bootstrap flow.
Deprecated provider helpers
The following RN Firebase-specific provider classes are deprecated in v25. Use OAuthProvider instead (matching firebase-js-sdk):
| Deprecated | Replacement |
|---|---|
AppleAuthProvider |
new OAuthProvider('apple.com') |
OIDCAuthProvider |
new OAuthProvider('oidc.<your-provider-id>') |
OIDCProvider |
OAuthProvider |
// Previously (deprecated)
import { AppleAuthProvider } from '@react-native-firebase/auth';
const credential = AppleAuthProvider.credential(idToken, rawNonce);
// Now
import { OAuthProvider } from '@react-native-firebase/auth';
const provider = new OAuthProvider('apple.com');
const credential = provider.credential({ idToken, rawNonce });// Previously (deprecated)
import { OIDCAuthProvider } from '@react-native-firebase/auth';
const credential = OIDCAuthProvider.credential('sample-provider', idToken, accessToken);
// Now
import { OAuthProvider } from '@react-native-firebase/auth';
const provider = new OAuthProvider('oidc.sample-provider');
const credential = provider.credential({ idToken, accessToken });AppleAuthProvider and OIDCAuthProvider remain exported for compatibility but will be removed in a future major release.
Action code URL parsing
ActionCodeURL.parseLink and parseActionCodeURL are implemented as synchronous pure URL parsers (matching firebase-js-sdk). They work on all platforms without calling the native bridge.
Signature changes
isSignInWithEmailLink(auth, emailLink)— returnsPromiseon iOS/Android (native bridge). The firebase-js-sdk returns a synchronousboolean. Port web code withawait isSignInWithEmailLink(auth, link)(or.then(...)).sendSignInLinkToEmail(auth, email, actionCodeSettings)—actionCodeSettingsis required in the modular API (matching firebase-js-sdk).- Namespaced email link (react-native-firebase convenience):
firebase.auth().sendSignInLinkToEmail(email, settings?)still accepts omitted settings. Internally_resolveActionCodeSettings()defaultsurlfromapp.options.authDomainandhandleCodeInApp: true. This is not platform-specific — only namespaced vs modular. Do not “fix” modular to match namespaced defaults. signInWithEmailLink(auth, email, emailLink?)— the third argument is optional, matching firebase-js-sdk.signInWithRedirect/linkWithRedirect— returnPromiseon native because provider flows resolve immediately with credentials instead of following the browser redirect contract.reauthenticateWithRedirect— returnsPromise<void>on native while still updatingcurrentUserafter the native provider flow completes.connectAuthEmulator(auth, url, options?)— whenoptionsis provided,disableWarningsis required (matching firebase-js-sdk).
Web APIs with matching types but different native runtime (iOS/Android)
These modular helpers are exported for firebase-js-sdk API parity. On iOS/Android they throw synchronously (or are not applicable) because native SDKs do not implement the browser persistence, redirect, or reCAPTCHA phone-link flows. Types match the firebase-js-sdk; behavior does not — see API reference @remarks on each symbol.
| API | Native iOS/Android behavior |
|---|---|
getRedirectResult |
Always throws — use immediate UserCredential from signInWithRedirect / linkWithRedirect instead |
setPersistence |
Always throws — native SDKs manage auth state |
useDeviceLanguage |
Always throws |
revokeAccessToken |
Always throws |
linkWithPhoneNumber |
Always throws |
reauthenticateWithPhoneNumber |
Always throws |
initializeAuth(app, deps?) accepts the firebase-js-sdk Dependencies type for API parity but ignores persistence, popup redirect resolver, and error-map dependencies on iOS/Android (see below).
Phone Auth (iOS/Android)
verifyPhoneNumber(auth, phoneNumber, ...)— iOS/Android only native listener flow (force-resend, auto-verification callbacks). On Other platforms usesignInWithPhoneNumber/ firebase-js-sdkPhoneAuthProviderinstead.signInWithPhoneNumber(auth, phoneNumber, appVerifier?)— modular API no longer accepts the formerforceResendfourth argument from React Native Firebase; useverifyPhoneNumberwhen you need the native listener / force-resend behavior.
Sign in with Apple
revokeToken(auth, authorizationCode)— React Native Firebase-specific modular helper for Apple's account-deletion requirement. Supported on iOS (nativerevokeTokenWithAuthorizationCode). Android and Web bridges resolve without performing revocation.- Do not confuse with
revokeAccessToken— that is firebase-js-sdk web-only OAuth token revocation and always throws on iOS/Android. - The namespaced
firebase.auth().revokeToken(authorizationCode)API remains available but is deprecated.
Auth instance surface
auth.tenantId = 'tenant-id'is now supported (delegates tosetTenantId).auth.authStateReady(),auth.beforeAuthStateChanged(...),auth.emulatorConfig, andauth.updateCurrentUser(user)are implemented on the Auth instance.auth.configruntime split (types unified): Declarations match firebase-js-sdkConfig, but runtime differs by platform:- iOS/Android: always
{}— native SDKs do not expose the web config object. - Other (Hermes/Web): firebase-js-sdk can populate
auth.config, but React Native Firebase does not delegate this yet. Do not readauth.configon native expectingapiKey/authDomain; usegetCustomAuthDomain(auth)on iOS/Android or app options on Other until delegation lands.
- iOS/Android: always
Credential providers
Provider credential factories return firebase-js-sdk-shaped credential classes (OAuthCredential, not internal type aliases) with toJSON() and static fromJSON() where applicable.
OAuthCredential.rawNonce— used for Sign in with Apple and Facebook limited-login flows (matches firebase-js-sdk credential options). OAuth 1.0 token secrets (e.g. Twitter) use the inheritedAuthCredential.secretbridge field instead ofrawNonce.RN Firebase credentials retain internal
token/secretbridge fields required by the native modules (implementation detail; omitted from generated API reference).OAuthProvider.credentialFromResult/credentialFromErrorand sibling provider helpers (GoogleAuthProvider,GithubAuthProvider,TwitterAuthProvider,FacebookAuthProvider,PhoneAuthProvider) always returnnullat runtime today. Declared types match firebase-js-sdk.- iOS/Android: no native extraction planned — credentials are not recoverable from native provider results.
- Other/Hermes: not delegated (firebase-js-sdk credential recovery is tied to popup/redirect flows).
- Other/Web: future implementation should delegate to firebase-js-sdk in the auth web bridge — do not invest in native iOS/Android bridge work for this.
GoogleAuthProvider.credential()throws when bothidTokenandaccessTokenare absent (matching firebase-js-sdk).FacebookAuthProvider.credential(token)matches firebase-js-sdk. React Native Firebase also exportscredential(token, secret)for Facebook limited-login nonce behavior — an intentional extension documented in compare:types.
Multi-factor
- Modular
multiFactor(user)now uses the user's auth instance instead of always callinggetAuth(), fixing secondary Firebase app usage. - Namespaced
firebase.auth().multiFactor(user)now correctly validates thatuseris thecurrentUser. TotpSecret.generateQrCodeUrl()returnsPromise<string>on iOS/Android (native bridge). firebase-js-sdk returns a synchronous string.TotpSecret.openInOtpApp(qrCodeUrl)— RN-only helper that deep-links into a One-Time Password authenticator app; not part of firebase-js-sdk.- Other platforms: MFA and TOTP flows are exercised in
tests/local-testsvia the firebase-js-sdk bridge — not a gap to “port” from native overloads.
Normalized modular return values
Modular helpers normalize several return shapes toward firebase-js-sdk:
UserCredentialincludes top-levelproviderIdandoperationType.- When the native bridge returns federated metadata,
additionalUserInfois attached as an enumerable property on modularUserCredentialobjects. Core fields match firebase-js-sdk (isNewUser,profile,providerId,username); extra native keys are copied onto the object for backwards compatibility. - Use
getAdditionalUserInfo(userCredential)for the canonical read (returnsAdditionalUserInfo | null, same shape as firebase-js-sdk). For TypeScript when you need provider-specific native extras, cast toAdditionalUserInfoNative(AdditionalUserInfo & Record<string, unknown>). checkActionCodenormalizesfromEmailtopreviousEmailand coerces multi-factor info shapes.signInWithPhoneNumberwraps confirmation results and validatesverificationIdpresence.
`initializeAuth`
initializeAuth(app, deps?) accepts the firebase-js-sdk Dependencies type for API parity, but persistence, popup redirect resolver, and error-map dependencies are ignored because native SDKs manage auth state.
Namespaced type adjustments
FirebaseAuthTypes.UserInfoprofile fields can be null.firebase.auth().configis typed asRecord<string, never>on the namespaced API (stricter than modularauth.config).
Cloud Messaging
PR: #9053
Notification permission APIs in @react-native-firebase/messaging are deprecated in v25. They are not Firebase-specific; dedicated libraries handle permissions more completely.
| Deprecated API | Use instead |
|---|---|
requestPermission(messaging, …) |
react-native-permissions or expo-notifications (Expo) |
hasPermission(messaging) |
Same |
registerDeviceForRemoteMessages(messaging) |
Same (platform setup) |
isDeviceRegisteredForRemoteMessages(messaging) |
Same |
AuthorizationStatus static on messaging |
Permission library equivalents |
These APIs still work at runtime but are marked @deprecated in TypeScript and documented for removal in a future major release. See #6283.
Automated migration checklist
Use this section when running scripted or agent-assisted upgrades from v24 → v25.
1. Upgrade dependencies
# Bump all @react-native-firebase/* packages to v25 together (monorepo versions are aligned)
yarn add @react-native-firebase/app@^25.0.0 …
cd ios && pod installEnsure Xcode 26.2+ for iOS builds.
2. Fix TypeScript by package
For each @react-native-firebase/ in your imports:
| Package | Search for | Replace with |
|---|---|---|
storage |
refFromURL, child(, FirebaseStorageTypes, .statics. |
ref(), root imports, modular functions |
database |
ServerValue, .orderByChild(, await goOffline |
serverTimestamp(), query/orderByChild functions, sync goOffline |
remote-config |
fetch(, setDefaults, setConfigSettings, .value, .source |
fetchConfig, defaultConfig/settings props, asString()/getSource() |
perf |
.newTrace, .newHttpMetric, await initializePerformance |
trace(), httpMetric(), sync initializePerformance |
installations |
.getId(), .getToken(), .delete() |
getId(), getToken(), deleteInstallations() |
app-check |
appCheck().getToken(), value import of FirebaseAppCheckTypes |
initializeAppCheck + getToken(), import type |
auth |
FirebaseAuthTypes, AppleAuthProvider, OIDCAuthProvider |
Root modular types, OAuthProvider |
messaging |
requestPermission, hasPermission |
react-native-permissions / expo-notifications |
3. Validate
yarn compile # root TypeScript compile
yarn compare:types # maintainers: per-package drift vs firebase-js-sdk
yarn tests:jest packages/<pkg>/__tests__ # targeted tests for touched packages4. Namespaced API users
If you only use firebase.storage(), firebase.auth(), etc. and do not import modular types:
- You may see deprecation warnings in IDE /
@deprecatedJSDoc. - Plan a gradual move to modular imports; namespaced removal is planned for a future major release.
- Runtime behavior should remain compatible for most flows.
Related PRs (v25 breaking changes since v24.0.0)
| Package | PR / commit |
|---|---|
| Storage | #8824 |
| App Check | #8889 |
| Remote Config | #8972 |
| Realtime Database | #8977 |
| Performance | 4aedfe883 |
| Installations | 739a4ca36 |
| Auth | #8991 |
| Messaging (deprecations) | #9053 |
| Native SDKs (Xcode) | c8c1fc105 |
Packages migrated to TypeScript without public API breaks in v25: @react-native-firebase/app-distribution (#8967), @react-native-firebase/ml (#9005).
Migrating To V26 (`docs/migrating-to-v26.mdx`)
title: Migrating to v26 previous: /migrating-to-v25 next: /migrating-to-v27
Version 26 removes the deprecated namespaced JavaScript API from selected packages. Each migrated package is modular-only: use getX(app?) and root-level helper functions from the package entry point. Namespaced default exports, firebase.<module>(), and Firebase*Types namespaces are removed from those packages.
If you are upgrading from v24 or earlier, complete Migrating to v25 first — v25 TypeScript alignment changes still apply.
Table of contents
- New Architecture requirement
- Platform behavior differences
- firebase-js-sdk API parity improvements
- General pattern
- App
- Machine Learning (ML)
- In-App Messaging
- Installations
- Cloud Messaging
- App Distribution
- Cloud Functions
- Performance Monitoring
- App Check
- Analytics
- Remote Config
- Crashlytics
- Realtime Database
- Cloud Storage
- Authentication
- Cloud Firestore
- Automated migration checklist
New Architecture requirement
From v26 onward, every React Native Firebase package with a native bridge is implemented as a Codegen TurboModule and requires React Native's New Architecture. The legacy bridge modules were removed in the coordinated v26 break.
If you cannot enable New Architecture yet, stay on v25 (or v23 if you still depend on legacy-architecture Cloud Functions — see below).
Exceptions (no New Architecture requirement)
| Package | Why |
|---|---|
@react-native-firebase/ai |
Pure JavaScript — uses the firebase-js-sdk web interop layer; no native TurboModule. |
@react-native-firebase/vertexai |
Pure JavaScript — same as ai; deprecated in favor of @react-native-firebase/ai. |
Cloud Functions (already required since v24)
@react-native-firebase/functions has required New Architecture since v24 (Migrating to v24 — Cloud Functions). v26 extends the same requirement to all remaining native modules.
Enable New Architecture
React Native CLI (Android) — set in android/gradle.properties:
newArchEnabled=trueReact Native CLI (iOS) — New Architecture is enabled when RCT_NEW_ARCH_ENABLED=1 during pod install (React Native sets this from newArchEnabled on recent templates). Follow the React Native New Architecture guide for your RN version.
Expo — enable in your app config (Expo SDK 52+):
{
"expo": {
"newArchEnabled": true
}
}Rebuild native projects after changing this (pod install, clean Android build).
If New Architecture is disabled
Native builds fail early with explicit guards:
- Android: Gradle scripts print
New Architecture support is required for @react-native-firebase/and fail the build. - iOS:
pod installfails withrequires New Architecture. Enable New Architecture to use this module.
Platform behavior differences
When migrating from firebase-js-sdk web examples, watch for these high-impact runtime divergences:
{/* prettier-ignore */}
| Area | firebase-js-sdk (web) | React Native Firebase |
|---|---|---|
| Auth | Browser persistence, redirects, reCAPTCHA, revokeAccessToken, useDeviceLanguage, linkWithPhoneNumber / reauthenticateWithPhoneNumber |
Native iOS/Android SDKs manage persistence. Several web-only helpers throw synchronously on React Native (setPersistence, getRedirectResult, revokeAccessToken, useDeviceLanguage, linkWithPhoneNumber, reauthenticateWithPhoneNumber). Use native provider flows instead. |
| Analytics | Cross-platform modular API | On-device conversion measurement helpers (initiateOnDeviceConversionMeasurement*) are iOS only; on Android and web the JS layer resolves without calling native (no-op). logTransaction (verified iOS in-app purchase events) is iOS only and rejects on other platforms. |
| Realtime Database | goOnline / goOffline are synchronous; web transport toggles |
goOnline / goOffline are synchronous through TurboModules, matching firebase-js-sdk. getServerTime, setPersistenceEnabled, and setPersistenceCacheSizeBytes are RN-specific. forceLongPolling / forceWebSockets throw — transport is native-controlled. |
| Phone Number Verification | N/A (Android SDK only) | Android only — all entry points throw on iOS and Web. |
| Cloud Storage | uploadBytes / uploadString from JS blobs; upload task controls return sync boolean |
putFile and writeToFile are native-only file-path APIs. UploadTask.pause() / .resume() / .cancel() also return sync boolean values through native TurboModules. |
| Cloud Messaging | Web push / service-worker surface | FCM token lifecycle, permissions, background handlers, and APNs token APIs are iOS only. Event delivery still uses the legacy native event proxy during the TurboModule migration; behavior matches pre-v26 releases but will change when Codegen events land in a future release. |
| Remote Config | reset() clears server and local state |
reset() is Android only — iOS does not clear activated, fetched, or default Remote Config values. setDefaultsFromResource loads from native resource files (.plist / XML). |
| Performance | initializePerformance returns synchronously; trace start/stop are sync |
initializePerformance is synchronous on RN (applies settings to the native instance). Trace, HTTP metric, and screen trace start/stop are synchronous through TurboModules, matching firebase-js-sdk. |
| Firestore | IndexedDB persistence, memoryLocalCache, persistentLocalCache, FieldValue maximum() / minimum() sentinels |
Local cache factories and IndexedDB APIs are web only. Persistence is controlled by the native Firestore SDK. initializeFirestore returns Firestore synchronously. FieldValue maximum() / minimum() are not exported yet because iOS SDK 12.15.0 lacks matching native factories. |
| App Check | reCAPTCHA version 3 / Enterprise web providers | Use ReactNativeFirebaseAppCheckProvider for Device Check, App Attest, Play Integrity, etc. Web reCAPTCHA provider classes have no RN equivalent. |
| RN-native-only modules | No web SDK | crashlytics, in-app-messaging, app-distribution, and ml are React Native only — no firebase-js-sdk modular surface. |
Per-package notes also appear in each module's usage page under Platform support.
firebase-js-sdk API parity improvements
v26 aligns React Native Firebase modular types and several runtime signatures with firebase-js-sdk where TurboModules removed bridge-forced Promise wrappers. Use this section when porting web SDK examples or when scripted upgrades hit TypeScript or runtime errors.
Migration rule: If a method below is sync, remove await and any .then() / .catch() chain on its return value — sync APIs return void or a value directly; calling .then() on void throws at runtime.
Synchronous APIs enabled by TurboModules
{/* prettier-ignore */}
| Method | Before (pre-v26 / legacy bridge) | After (v26) | Notes |
|---|---|---|---|
registerVersion(library, version, variant?) |
Promise<void> (web) |
void — throws on RN |
Web-only on RN; remove await if copied from web samples |
isSignInWithEmailLink(auth, emailLink) |
Promise |
boolean |
Remove await |
TotpSecret.generateQrCodeUrl(accountName?, issuer?) |
Promise<string> |
string |
Remove await; omitted args default from current user / app name |
trace(…).start() / .stop() |
Promise<null> |
void |
Remove await on perf trace lifecycle |
httpMetric(…).start() / .stop() |
Promise<null> |
void |
Same as traces |
ScreenTrace.start() / .stop() |
Promise<null> |
void |
Same as traces |
startScreenTrace(performance, screenName) |
Promise<ScreenTrace> |
ScreenTrace |
Remove await |
goOnline(db) / goOffline(db) |
Promise<void> |
void |
Remove await |
UploadTask.pause() / .resume() / .cancel() |
Promise |
boolean |
Remove await; use the returned boolean directly |
Type parity improvements
{/* prettier-ignore */}
| Export / method | Before | After | Notes |
|---|---|---|---|
onSnapshotsInSync(firestore, observer) |
next?: () => void; error?: Error |
next?: (value: void) => void; error?: FirestoreError |
Callback overload onSnapshotsInSync(firestore, () => {}) unchanged |
uploadBytes(ref, data, metadata?) |
Return type TaskResult |
UploadResult |
Alias rename only |
uploadBytesResumable(ref, data, metadata?) |
Return type Task |
UploadTask |
Alias rename only |
| Storage / Remote Config error callbacks | NativeFirebaseError |
FirebaseError / StorageError |
NativeFirebaseError remains assignable to FirebaseError |
AppCheckTokenListener |
Not exported | Exported type alias | Matches firebase-js-sdk observer typing |
FunctionsError, FunctionsErrorCodeCore |
Missing or misaligned | Exported / aligned | Registry + compare-types config |
firestore/pipelines (StageOptions, TimeGranularity, isType, …) |
Declaration drift | Aligned to SDK .d.ts |
Type-only; no call-shape change |
Synchronous modular return values
{/* prettier-ignore */}
| Method | Before | After | Notes |
|---|---|---|---|
logEvent(analytics, …) |
Promise<void> |
void |
Fire-and-forget; remove await / .then() |
initializeAppCheck(app?, options?) |
Promise<AppCheck> |
AppCheck |
Returns handle immediately; provider setup continues natively |
initializeFirestore(app, settings, databaseId?) |
Promise<Firestore> |
Firestore |
Returns instance immediately; settings() runs on native bridge |
getRemoteConfig(app?, options?) |
(app?) only |
(app?, options?: RemoteConfigOptions) |
options accepted for parity; no-op on native |
aggregateFieldEqual() |
Not exported | Exported | Aggregate query helper |
LastFetchStatus literals |
— | — | Unchanged — native still uses no_fetch_yet / throttled (documented drift) |
Firestore parity additions
{/* prettier-ignore */}
| Export / method | Before | After | Notes |
|---|---|---|---|
TransactionOptions |
Not exported | Exported | Type for transaction retry options |
runTransaction(firestore, updateFunction, options?) |
No options argument | Accepts options?: TransactionOptions |
{ maxAttempts?: number } on native iOS and Android; omitted options use the SDK default of 5 retries; explicit values < 1 throw Max attempts must be at least 1 (firebase-js-sdk parity) |
aggregateQuerySnapshotEqual() |
Not exported | Exported | Aggregate query snapshot equality helper, alongside aggregateFieldEqual() |
maximum(n) / minimum(n) FieldValue sentinels |
Exported by firebase-js-sdk 12.15.0 | Not exported by RNFB yet | Android SDK 34.15.0 has native factories, but iOS Firebase Firestore SDK 12.15.0 does not; RNFB waits for cross-platform parity |
Observer and Promise pitfalls
{/* prettier-ignore */}
| Pitfall | Symptom | Fix |
|---|---|---|
.then() on sync API |
TypeError: … .then is not a function |
Use direct call: logEvent(…) not logEvent(…).then(…) |
await on sync API |
Unnecessary microtask delay; misleading types in strict TS | Drop await where the table above marks the API sync |
onConfigUpdate(remoteConfig, observer) |
Runtime throw: observer must include both next and error functions |
Pass { next: (update) => {…}, error: (err) => {…} } — do not omit error |
onSnapshotsInSync observer form |
Type error on error callback |
Type error as (error: FirestoreError) => void, or use the () => void callback overload |
runTransaction(..., { maxAttempts: 0 }) or negative |
Runtime throw: Max attempts must be at least 1 |
Omit options for the default 5 attempts, or pass maxAttempts: 1 or higher |
General pattern
For each package listed in this guide:
- Remove default export /
firebase.<module>()usage — import modular helpers from the package root. - Replace
Firebase*Typesnamespace imports with root types (InAppMessaging,Installations,FirebaseML, etc.). - Prefer free functions (
getId(installations),setMessagesDisplaySuppressed(inAppMessaging, enabled)) over instance methods on service objects.
Modular-only in v26: @react-native-firebase/app, @react-native-firebase/ml, @react-native-firebase/in-app-messaging, @react-native-firebase/installations, @react-native-firebase/messaging, @react-native-firebase/app-distribution, @react-native-firebase/functions, @react-native-firebase/perf, @react-native-firebase/app-check, @react-native-firebase/remote-config, @react-native-firebase/crashlytics, @react-native-firebase/database, @react-native-firebase/storage, @react-native-firebase/analytics, @react-native-firebase/auth, and @react-native-firebase/firestore. Other packages may still expose the namespaced API with deprecation warnings; modular imports remain the supported path.
App
The namespaced API for @react-native-firebase/app has been removed. This package is modular-only — use named exports such as getApp(), initializeApp(), and getUtils().
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
Default export firebase |
Named exports from @react-native-firebase/app |
firebase.app(name?) |
getApp(name?) |
firebase.apps |
getApps() |
firebase.initializeApp(options, name?) |
initializeApp(options, name?) |
firebase.utils(app?) |
getUtils(app?) |
firebase.utils.FilePath |
FilePath (named export) |
firebase.SDK_VERSION |
SDK_VERSION (named export) |
firebase.setLogLevel(...) |
setLogLevel(...) |
firebase.<module>() accessors on the default export |
Import modular helpers from each @react-native-firebase/* package |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
firebase.app().name;
firebase.initializeApp(options, 'secondary');
firebase.utils().FilePath.DOCUMENT_DIRECTORY;// Now
import { getApp, initializeApp, getUtils, FilePath } from '@react-native-firebase/app';
getApp().name;
initializeApp(options, 'secondary');
getUtils().FilePath.DOCUMENT_DIRECTORY;
// or
FilePath.DOCUMENT_DIRECTORY;Breaking: Android Play Services availability Promise behavior
On Android, makePlayServicesAvailable() now rejects when the Play Services availability task is canceled or fails. Previously, the call always resolved even when the update flow was not completed. Update callers to handle rejection:
import { getUtils } from '@react-native-firebase/app';
try {
await getUtils().makePlayServicesAvailable();
} catch (error) {
// Handle canceled or failed Play Services update
}Machine Learning (ML)
The namespaced API for @react-native-firebase/ml has been removed. This package is modular-only — use getML(app?).
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.ml() |
getML() or getML(app) |
Default export ml() |
getML() or getML(app) |
FirebaseMLTypes namespace |
Import FirebaseML from package root |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import ml from '@react-native-firebase/ml';
firebase.ml().app.name;
ml().app.name;// Now
import { getApp } from '@react-native-firebase/app';
import { getML } from '@react-native-firebase/ml';
getML().app.name; // default app
getML(getApp('secondaryFromNative')).app.name;In-App Messaging
The namespaced API for @react-native-firebase/in-app-messaging has been removed. This package is modular-only — use getInAppMessaging() and the root-level helper functions.
There is no firebase/in-app-messaging entry in the firebase-js-sdk modular surface; React Native Firebase follows the same modular service-instance pattern used for other native-only modules.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.inAppMessaging() |
getInAppMessaging() |
Default export inAppMessaging() |
getInAppMessaging() |
FirebaseInAppMessagingTypes |
Import InAppMessaging and helpers (setMessagesDisplaySuppressed, etc.) from root |
| Instance-only usage without modular helpers | Prefer free functions: setMessagesDisplaySuppressed(inAppMessaging, enabled), etc. |
Example: suppressing messages during setup
// Previously (removed)
import firebase from '@react-native-firebase/app';
import inAppMessaging from '@react-native-firebase/in-app-messaging';
await firebase.inAppMessaging().setMessagesDisplaySuppressed(true);
// or
await inAppMessaging().setMessagesDisplaySuppressed(true);// Now
import {
getInAppMessaging,
setMessagesDisplaySuppressed,
} from '@react-native-firebase/in-app-messaging';
await setMessagesDisplaySuppressed(getInAppMessaging(), true);See In-App Messaging usage for additional examples.
Installations
The namespaced API for @react-native-firebase/installations has been removed. This package is modular-only — use getInstallations() and the root-level helper functions.
Modular getInstallations() returns a firebase-js-sdk-shaped Installations object exposing only app. Use modular helper functions instead of instance methods.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.installations() |
getInstallations() |
Default export installations() |
getInstallations() |
FirebaseInstallationsTypes |
Import Installations and helpers (getId, getToken, deleteInstallations) from root |
installations.getId() / .getToken() / .delete() |
getId(installations), getToken(installations), deleteInstallations(installations) |
Breaking changes (modular call shape)
| Before | Now |
|---|---|
installations.getId() |
getId(installations) |
installations.getToken() |
getToken(installations) |
installations.delete() |
deleteInstallations(installations) — argument is required |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import installations from '@react-native-firebase/installations';
const id = await firebase.installations().getId();
// or
const id = await installations().getId();// Now
import { getInstallations, getId } from '@react-native-firebase/installations';
const installations = getInstallations();
const id = await getId(installations);See Installations usage for additional examples.
Cloud Messaging
The namespaced API for @react-native-firebase/messaging has been removed. This package is modular-only — use getMessaging() and the root-level helper functions.
Modular getMessaging() returns a firebase-js-sdk-shaped Messaging object. Prefer free functions (getToken(messaging), onMessage(messaging, listener), etc.) over calling methods on the service instance.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.messaging() |
getMessaging() |
Default export messaging() |
getMessaging() |
FirebaseMessagingTypes |
Import Messaging, RemoteMessage, and helpers from package root |
messaging.getToken() / .onMessage() / etc. |
getToken(messaging), onMessage(messaging, listener), etc. |
messaging.setDeliveryMetricsExportToBigQuery() |
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, enabled) |
firebase.messaging.SDK_VERSION / messaging.SDK_VERSION |
SDK_VERSION top-level export from package root |
Example: foreground messages
// Previously (removed)
import firebase from '@react-native-firebase/app';
import messaging from '@react-native-firebase/messaging';
firebase.messaging().onMessage(message => {
console.log(message.data);
});
// or
messaging().onMessage(message => {
console.log(message.data);
});// Now
import { getMessaging, onMessage } from '@react-native-firebase/messaging';
onMessage(getMessaging(), message => {
console.log(message.data);
});Example: delivery metrics to BigQuery
// Previously (removed)
await firebase.messaging().setDeliveryMetricsExportToBigQuery(true);// Now
import {
getMessaging,
experimentalSetDeliveryMetricsExportedToBigQueryEnabled,
} from '@react-native-firebase/messaging';
await experimentalSetDeliveryMetricsExportedToBigQueryEnabled(getMessaging(), true);See Cloud Messaging usage for additional examples.
iOS APNs registration (ARM64 Simulator + new Promise rejections)
On ARM64 iOS Simulator (Apple Silicon), React Native Firebase no longer calls UIKitregisterForRemoteNotifications from messaging registration and auto-registration paths
(including the TurboModule registerDeviceForRemoteMessages path, requestPermission's APNs
side-effect, and native auto-register on app launch). Calling that UIKit API can block the main
thread indefinitely. Physical iOS devices are unchanged — they still call UIKitregisterForRemoteNotifications as before.
This is intentional product policy so the main thread stays responsive on Simulator. You will
not receive a real APNs device token on ARM64 Simulator; use a physical device for end-to-end
push registration and delivery.
New possible Promise rejections
Prior releases could hang forever waiting for APNs registration (especially when the main thread
was wedged) and did not reject with the codes below in the same situations. Apps that assumedregisterDeviceForRemoteMessages always resolved (or never rejected) must handle these errors.
`messaging/registration-timeout`
- When: After about 10 seconds, a timer on a global queue (not the main queue) rejects
the in-flight registration Promise when APNs registration has not settled. - APIs: Surfaces on
registerDeviceForRemoteMessagesonly. requestPermission: On ARM64 Simulator, the APNs UIKit side-effect is skipped; the
permission Promise still resolves withAuthorizationStatusand does not reject with this
code.- ARM64 Simulator: Expected when you call
registerDeviceForRemoteMessages— UIKit register is
skipped, the Promise stays pending, then the global-queue timer rejects. - Physical device: Possible if the system never delivers a registration success/failure
callback within about 10 seconds (for example missing notification permission, or a blocked main
thread). - Code / message:
messaging/registration-timeout—registerDeviceForRemoteMessages timed out waiting for APNs device registration. The system did not respond — possibly missing notification permission, or the main thread is blocked (common on ARM64 Simulator).
`messaging/registration-superseded`
- When: A newer
registerDeviceForRemoteMessagescall starts while a prior attempt is still in
flight; the earlier Promise is rejected so it is not orphaned. - APIs: Surfaces on
registerDeviceForRemoteMessagesonly (overlapping calls). - Code / message:
messaging/registration-superseded—registerDeviceForRemoteMessages was called again before the previous APNs registration attempt settled.
Further usage notes: Auto Registration (iOS),
iOS Messaging Setup. Maintainer platform detail:
iOS APNs registration on Simulator.
App Distribution
The namespaced API for @react-native-firebase/app-distribution has been removed. This package is modular-only — use getAppDistribution() and the root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.appDistribution() |
getAppDistribution() |
Default export appDistribution() |
getAppDistribution() |
FirebaseAppDistributionTypes |
Import AppDistribution, AppDistributionRelease from package root |
appDistribution.isTesterSignedIn() / etc. |
isTesterSignedIn(appDistribution), signInTester(appDistribution), checkForUpdate(appDistribution), signOutTester(appDistribution) |
firebase.appDistribution.SDK_VERSION |
SDK_VERSION top-level export from package root |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import appDistribution from '@react-native-firebase/app-distribution';
await firebase.appDistribution().isTesterSignedIn();// Now
import { getAppDistribution, isTesterSignedIn } from '@react-native-firebase/app-distribution';
const appDistribution = getAppDistribution();
await isTesterSignedIn(appDistribution);Cloud Functions
The namespaced API for @react-native-firebase/functions has been removed. This package is modular-only — use getFunctions() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.functions() |
getFunctions() or getFunctions(app, regionOrCustomDomain) |
Default export functions() |
getFunctions() |
FirebaseFunctionsTypes |
Import Functions, HttpsCallable, HttpsErrorCode, etc. from package root |
functions().httpsCallable() |
httpsCallable(functions, name, options?) |
functions().useEmulator() |
connectFunctionsEmulator(functions, host, port) |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import functions from '@react-native-firebase/functions';
await firebase.functions().httpsCallable('myFn')({ foo: 'bar' });// Now
import { getFunctions, httpsCallable } from '@react-native-firebase/functions';
const functions = getFunctions();
await httpsCallable(functions, 'myFn')({ foo: 'bar' });Performance Monitoring
The namespaced API for @react-native-firebase/perf has been removed. This package is modular-only — use getPerformance() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.perf() |
getPerformance() |
Default export perf() |
getPerformance() |
FirebasePerformanceTypes |
Import FirebasePerformance, PerformanceTrace, etc. from package root |
perf().newTrace() |
trace(performance, name) |
perf().newHttpMetric() |
httpMetric(performance, url, httpMethod) |
Signature changes
Trace,HttpMetric, andScreenTracestart()/stop()now returnvoidsynchronously (previouslyPromise<null>), matching the firebase-js-sdk webPerformanceTrace. The underlying native calls are in-memory, so noawaitis required — remove anyawaiton these calls.startScreenTrace(performance, screenName)and the internalstartTrace(name)helper now return the trace instance synchronously instead of aPromise.
App Check
The namespaced API for @react-native-firebase/app-check has been removed. This package is modular-only — use getAppCheck() / initializeAppCheck() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.appCheck() |
getAppCheck() or initializeAppCheck(app, options) |
Default export appCheck() |
getAppCheck() |
FirebaseAppCheckTypes |
Import AppCheck, AppCheckTokenResult, etc. from package root |
appCheck().getToken() |
getToken(appCheck, forceRefresh?) |
Signature changes
initializeAppCheck(app?, options?)returnsAppChecksynchronously (previouslyPromise<AppCheck>). Native provider setup continues in the background — removeawaitand do not chain.then().
Analytics
The namespaced API for @react-native-firebase/analytics has been removed. This package is modular-only — use getAnalytics() and root-level helper functions.
Analytics supports only the default Firebase app (same as before). Calling getAnalytics(secondaryApp) throws.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.analytics() |
getAnalytics() |
Default export analytics() |
getAnalytics() |
FirebaseAnalyticsTypes |
Import Analytics, event parameter types, etc. from package root |
analytics().logEvent(...) |
logEvent(analytics, ...) |
analytics().setUserId(...) etc. |
setUserId(analytics, ...), setConsent(analytics, ...), etc. |
Deprecated helper events (logScreenView, logPurchase, …) |
Still exported as modular helpers; prefer logEvent(analytics, 'screen_view', params) |
Signature changes
logEvent(analytics, …)returnsvoidsynchronously (previouslyPromise<void>). Removeawaitand.then()chains.
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import analytics from '@react-native-firebase/analytics';
await firebase.analytics().logEvent('screen_view', { screen_name: 'Home' });
await analytics().setUserId('user-123');// Now
import { getAnalytics, logEvent, setUserId } from '@react-native-firebase/analytics';
const analytics = getAnalytics();
logEvent(analytics, 'screen_view', { screen_name: 'Home' });
await setUserId(analytics, 'user-123');See Analytics usage for additional examples.
Remote Config
The namespaced API for @react-native-firebase/remote-config has been removed. This package is modular-only — use getRemoteConfig() and root-level helper functions.
Modular getRemoteConfig() returns a firebase-js-sdk-shaped RemoteConfig object with app, settings, defaultConfig, fetchTimeMillis, and lastFetchStatus. Use modular helper functions for fetch/activate/getters; assign remoteConfig.settings and remoteConfig.defaultConfig instead of removed modular setConfigSettings() / setDefaults() helpers.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.remoteConfig() |
getRemoteConfig() |
Default export remoteConfig() |
getRemoteConfig() |
FirebaseRemoteConfigTypes |
Import RemoteConfig, Value, etc. from package root |
remoteConfig().activate() etc. |
activate(remoteConfig), fetchConfig(remoteConfig), getValue(remoteConfig, key), etc. |
remoteConfig.LastFetchStatus / .ValueSource on namespace |
LastFetchStatus, ValueSource named exports |
Breaking changes (modular call shape)
| Before | Now |
|---|---|
remoteConfig().fetch() |
fetchConfig(remoteConfig) |
remoteConfig().setConfigSettings({ ... }) |
remoteConfig.settings = { ... } |
remoteConfig().setDefaults({ ... }) |
remoteConfig.defaultConfig = { ... } |
remoteConfig().onConfigUpdated(listener) |
onConfigUpdate(remoteConfig, observer) |
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import remoteConfig from '@react-native-firebase/remote-config';
await firebase.remoteConfig().fetchAndActivate();
const value = firebase.remoteConfig().getValue('key').asString();// Now
import { getRemoteConfig, fetchAndActivate, getValue } from '@react-native-firebase/remote-config';
const remoteConfig = getRemoteConfig();
await fetchAndActivate(remoteConfig);
const value = getValue(remoteConfig, 'key').asString();See Remote Config usage for additional examples.
Crashlytics
The namespaced API for @react-native-firebase/crashlytics has been removed. This package is modular-only — use getCrashlytics() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.crashlytics() |
getCrashlytics() |
Default export crashlytics() |
getCrashlytics() |
FirebaseCrashlyticsTypes |
Import Crashlytics from package root |
crashlytics().log() |
log(crashlytics, message) |
crashlytics().recordError() |
recordError(crashlytics, error, jsErrorName?) |
Realtime Database
The namespaced API for @react-native-firebase/database has been removed. This package is modular-only — use getDatabase() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.database() |
getDatabase() or getDatabase(app, url?) |
Default export database() |
getDatabase() |
FirebaseDatabaseTypes |
Import Database, DatabaseReference, etc. from package root |
database().ref() |
ref(database, path?) |
database().refFromURL() |
refFromURL(database, url) |
Signature changes
goOnline(db)andgoOffline(db)(and the database instance methods) now returnvoidsynchronously (previouslyPromise<void>), matching firebase-js-sdk. Remove anyawaiton these calls.
Cloud Storage
The namespaced API for @react-native-firebase/storage has been removed. This package is modular-only — use getStorage() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.storage() |
getStorage() or getStorage(app, bucketUrl?) |
Default export storage() |
getStorage() |
FirebaseStorageTypes |
Import FirebaseStorage, StorageReference, etc. from package root |
storage().ref() |
ref(storage, path?) |
storageRef.put() |
uploadBytesResumable(storageRef, data, metadata?) |
Signature changes
UploadTask.pause(),UploadTask.resume(), andUploadTask.cancel()now returnbooleansynchronously (previouslyPromise), matching firebase-js-sdk task semantics. Removeawait,.then(), and.catch()from these control calls and use the returned boolean directly.cancel()delegates to the native SDK. Android cancels active uploads; iOS active-upload cancel follows the current Firebase Storage iOS SDK 12.15.0 behavior tracked in firebase-ios-sdk#16353.
Authentication
The namespaced API for @react-native-firebase/auth has been removed. This package is modular-only — use getAuth() / initializeAuth() and root-level helper functions.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.auth() |
getAuth() or getAuth(app) |
Default export auth() |
getAuth() |
FirebaseAuthTypes namespace |
Import Auth, User, UserCredential, etc. from package root |
auth().signInWithEmailAndPassword(...) |
signInWithEmailAndPassword(getAuth(), ...) |
auth().useEmulator(url) |
connectAuthEmulator(getAuth(), url, options?) |
firebase.auth.EmailAuthProvider |
EmailAuthProvider (named export) |
Signature changes
isSignInWithEmailLink(auth, emailLink)now returnsbooleansynchronously, matching firebase-js-sdk.TotpSecret.generateQrCodeUrl(accountName?, issuer?)now returnsstringsynchronously, matching firebase-js-sdk. WhenaccountNameorissueris omitted, React Native Firebase fills the same defaults from the current user email and Firebase app name.
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import auth from '@react-native-firebase/auth';
firebase.auth().signOut();
auth().currentUser;// Now
import { getAuth, signOut } from '@react-native-firebase/auth';
const auth = getAuth();
await signOut(auth);
auth.currentUser;Cloud Firestore
The namespaced API for @react-native-firebase/firestore has been removed. This package is modular-only — use getFirestore() / initializeFirestore() and root-level helper functions. The @react-native-firebase/firestore/pipelines subpath export is unchanged.
Removed namespaced API
| Removed | Replacement (modular) |
|---|---|
firebase.firestore() |
getFirestore() or getFirestore(app, databaseId?) |
Default export firestore() |
getFirestore() |
FirebaseFirestoreTypes namespace |
Import Firestore, DocumentReference, Query, etc. from package root |
firestore().collection(...) |
collection(getFirestore(), ...) |
firestore().doc(...) |
doc(getFirestore(), ...) |
firestore().batch() |
writeBatch(getFirestore()) |
firestore().runTransaction(...) |
runTransaction(getFirestore(), updateFunction, options?) |
firestore().useEmulator(...) |
connectFirestoreEmulator(getFirestore(), ...) |
firestore().settings(...) |
initializeFirestore(app, settings, databaseId?) |
firestore.FieldValue / firestore.Timestamp |
FieldValue, Timestamp, FieldPath, Bytes, GeoPoint, Filter (named exports) |
firestore.Blob |
Bytes |
Signature changes
initializeFirestore(app, settings, databaseId?)returnsFirestoresynchronously (previouslyPromise<Firestore>). Removeawaitand.then(); settings apply on the native bridge after return.TransactionOptionsis now exported.runTransaction(firestore, updateFunction, options?)accepts{ maxAttempts?: number }and passes the retry limit to the native iOS and Android Firestore SDKs. Whenoptionsis omitted, the native default applies (5 attempts, matching firebase-js-sdkrunTransaction). WhenmaxAttemptsis provided explicitly, values below 1 throw synchronously withMax attempts must be at least 1— the same validation as firebase-js-sdk.aggregateFieldEqual()andaggregateQuerySnapshotEqual()are now exported for aggregate query equality checks (firebase-js-sdk parity).- FieldValue
maximum(n)andminimum(n)sentinels from firebase-js-sdk 12.15.0 are not exported yet. Android Firebase Firestore SDK 34.15.0 supports them, but iOS Firebase Firestore SDK 12.15.0 does not expose matchingFIRFieldValuefactories, so React Native Firebase waits for cross-platform support.
Example
// Previously (removed)
import firebase from '@react-native-firebase/app';
import firestore from '@react-native-firebase/firestore';
firebase.firestore().collection('users').doc('alice').set({ name: 'Alice' });
firestore.FieldValue.serverTimestamp();// Now
import {
getFirestore,
collection,
doc,
setDoc,
serverTimestamp,
} from '@react-native-firebase/firestore';
const db = getFirestore();
await setDoc(doc(collection(db, 'users'), 'alice'), {
name: 'Alice',
createdAt: serverTimestamp(),
});See Firestore usage for additional examples.
Automated migration checklist
Use this section when running scripted or agent-assisted upgrades to v26 for modular-only packages.
1. Upgrade dependencies
# Bump all @react-native-firebase/* packages to v26 together (monorepo versions are aligned)
yarn add @react-native-firebase/app@^26.0.0 …
cd ios && pod install2. Fix imports by package
For each modular-only package you use:
| Package | Search for | Replace with |
|---|---|---|
app |
default firebase import, firebase.app(), firebase.apps, firebase.initializeApp(), firebase.utils(), firebase.SDK_VERSION |
getApp(), getApps(), initializeApp(), getUtils(), FilePath, SDK_VERSION, setLogLevel, etc. |
ml |
firebase.ml(), default ml(), FirebaseMLTypes |
getML(), root FirebaseML type |
in-app-messaging |
firebase.inAppMessaging(), default inAppMessaging(), FirebaseInAppMessagingTypes |
getInAppMessaging(), root modular helpers (setMessagesDisplaySuppressed, etc.) |
installations |
firebase.installations(), default installations(), .getId(), .getToken(), .delete(), FirebaseInstallationsTypes |
getInstallations(), getId(), getToken(), deleteInstallations() |
messaging |
firebase.messaging(), default messaging(), FirebaseMessagingTypes, instance methods |
getMessaging(), root helpers (getToken, onMessage, etc.), SDK_VERSION, experimentalSetDeliveryMetricsExportedToBigQueryEnabled |
app-distribution |
firebase.appDistribution(), default appDistribution(), FirebaseAppDistributionTypes, instance methods |
getAppDistribution(), isTesterSignedIn, signInTester, checkForUpdate, signOutTester, SDK_VERSION |
functions |
firebase.functions(), default functions(), FirebaseFunctionsTypes, instance methods |
getFunctions(), httpsCallable, httpsCallableFromUrl, connectFunctionsEmulator, HttpsErrorCode |
perf |
firebase.perf(), default perf(), FirebasePerformanceTypes, instance methods |
getPerformance(), trace, httpMetric, newScreenTrace, startScreenTrace, initializePerformance |
app-check |
firebase.appCheck(), default appCheck(), FirebaseAppCheckTypes, instance methods |
getAppCheck(), initializeAppCheck, getToken, getLimitedUseToken, setTokenAutoRefreshEnabled, onTokenChanged, CustomProvider |
analytics |
firebase.analytics(), default analytics(), FirebaseAnalyticsTypes, instance methods |
getAnalytics(), logEvent, setUserId, setConsent, getAppInstanceId, getSessionId, etc. |
remote-config |
firebase.remoteConfig(), default remoteConfig(), FirebaseRemoteConfigTypes, instance methods |
getRemoteConfig(), activate, fetchConfig, fetchAndActivate, getValue, getAll, onConfigUpdate, LastFetchStatus, ValueSource |
crashlytics |
firebase.crashlytics(), default crashlytics(), FirebaseCrashlyticsTypes, instance methods |
getCrashlytics(), log, recordError, setUserId, setAttribute, setAttributes, setCrashlyticsCollectionEnabled, etc. |
database |
firebase.database(), default database(), FirebaseDatabaseTypes, instance methods |
getDatabase(), ref, refFromURL, onValue, runTransaction, connectDatabaseEmulator, etc. |
storage |
firebase.storage(), default storage(), FirebaseStorageTypes, instance/reference methods |
getStorage(), ref, uploadBytesResumable, getDownloadURL, connectStorageEmulator, StringFormat, TaskEvent, TaskState |
firestore |
firebase.firestore(), default firestore(), FirebaseFirestoreTypes, instance methods |
getFirestore(), doc, collection, setDoc, writeBatch, runTransaction, connectFirestoreEmulator, FieldValue, Timestamp, Bytes, SDK_VERSION |
Also remove await, .then(), and .catch() from UploadTask.pause(), UploadTask.resume(), and UploadTask.cancel(). For Firestore transactions, import TransactionOptions when you pass { maxAttempts } (omit options for the default 5 retries; do not pass 0 or negative values). Import aggregateFieldEqual() / aggregateQuerySnapshotEqual() for aggregate equality checks.
3. Validate
yarn compile
yarn tests:jest packages/<pkg>/__tests__Migrating To V27 (`docs/migrating-to-v27.mdx`)
title: Migrating to v27 previous: /migrating-to-v26 next: /typescript
Version 27 is a native and JS SDK major plus several earlier breaking corrections:
Upstream SDK majors (new in this release)
| Platform | Pin | Floor / install change |
|---|---|---|
| Android | Firebase BoM 35.0.0 | minSdk 24 (was 23); Kotlin Gradle plugin ≥ 2.4.0 |
| Apple | Firebase iOS SDK 13.0.0 (SPM) | macOS 11.0 (was 10.15); SPM-only Firebase (CocoaPods path removed) |
| JS | firebase 13.0.0 |
AI Logic API removals / renames (see below) |
- Android — BoM 35 requires API 24+. Update
minSdkVersion/sdkVersionsoverrides to 24. Raise the Kotlin Gradle plugin to ≥ 2.4.0 (firebase-auth25 ships Kotlin 2.4.0 metadata). See Platforms. - Apple — Firebase 13 is distributed only via Swift Package Manager. Remove
$RNFirebaseDisableSPM/ ExpodisableSPM. Useuse_frameworks! :linkage => :dynamic. See iOS SPM Support. Google Sign-In + Firebase 13 may still hit App Check resolve conflicts — see Ecosystem compatibility tips and iOS SPM Support § Google Sign-In caveat. - JS / AI — Align with Firebase JS SDK 13 /
@firebase/ai@3: useAgentPlatformBackend(default locationglobal) instead of removedVertexAIBackend; templategenerateContenttakes aTemplateRequest; removeLiveSession.sendMediaChunks/sendMediaStream(use realtime senders); droptotalBillableCharactersand related removed fields.
Other v27 breaks (already on this line)
- Cloud Messaging — four documented runtime contracts are enforced after previous accidental shapes (#9246, #9247, #9252, #9254).
- Imagen API removed from
@react-native-firebase/aiafter Google shut down the Imagen models as a service on 2026-08-17. Generate images with a Gemini image model throughgetGenerativeModel()instead. - App (iOS) —
initializeAppreadsautomaticDataCollectionEnabledas a real boolean, and public App headers no longer re-export FirebaseCore / Photos (#9337). - ML package removed —
@react-native-firebase/mlis discontinued and no longer published with v27. - FunctionsError (web/macOS) — earlier JS SDK enrichment of
FunctionsError.message/customData.urlonPlatform.other(see section below; still applies under JS 13).
If you are upgrading from v25 or earlier, complete Migrating to v26 first — the namespaced API removal and New Architecture requirement still apply.
Table of contents
- Agent-assisted migration
- Upstream SDK majors
- Firebase JS / FunctionsError
- Cloud Messaging
- AI Logic breaking removals
- Removed Imagen API
- App (iOS)
- Removed ML package
- Ecosystem compatibility tips
- Automated migration checklist
Upstream SDK majors
Migration actions
- Bump all
@react-native-firebase/*packages to v27 together. - Android: set
minSdkVersion/ anyreact-nativeversions.android.minSdkoverride to 24; setkotlinVersion/ the Kotlin Gradle plugin to ≥ 2.4.0. - iOS: remove
$RNFirebaseDisableSPM = trueand Expoios.disableSPM; ensureuse_frameworks! :linkage => :dynamic(or ExpouseFrameworks: "dynamic"); raise macOS deployment target to 11.0 if you ship macOS. - JS: ensure the app resolves
firebase@13(RNFB pins it on@react-native-firebase/app). - AI: apply the AI Logic breaking removals below.
AI Logic breaking removals
These match Firebase JS SDK 13 / @firebase/ai@3:
| Removed / changed | Replacement |
|---|---|
VertexAIBackend / BackendType.VERTEX_AI |
AgentPlatformBackend / BackendType.AGENT_PLATFORM (default location global, was us-central1 for Vertex) |
generateContent(templateId, vars, …) positional |
generateContent({ templateId, templateVariables, toolConfig? }) (TemplateRequest) |
LiveSession.sendMediaChunks / sendMediaStream |
sendTextRealtime / sendAudioRealtime / sendVideoRealtime |
CountTokensResponse.totalBillableCharacters |
Use totalTokens |
Part without type |
Discriminated union with type: 'text' | 'inlineData' | … |
GenerationConfig / LiveGenerationConfig sampling fields (temperature, topP, topK, presencePenalty, frequencyPenalty) and candidateCount remain on the types but are @deprecated for Gemini 3.x / 4.x — omit them for those models. They are not removed in v27.
import { getAI, AgentPlatformBackend, getTemplateGenerativeModel } from '@react-native-firebase/ai';
const ai = getAI(getApp(), { backend: new AgentPlatformBackend() }); // location defaults to global
const templates = getTemplateGenerativeModel(ai);
await templates.generateContent({
templateId: 'my-template',
templateVariables: { name: 'Ada' },
});Firebase JS / FunctionsError
Agent-assisted migration
This guide is written to be complete enough for an automated first pass. We recommend feeding this document to your coding agent, then asking it to analyze your codebase against each relevant section below and produce a concrete change list (or PR) for the packages you use. The Automated migration checklist at the end is structured for that workflow.
PR: #9218
React Native Firebase pins firebase-js-sdk 13.x. On web and macOS (Platform.other), Cloud Functions uses the JS SDK callable path. That path enriches FunctionsError (aliased as HttpsError in React Native Firebase) — behavior introduced in JS SDK 12.18.0 and still present in 13:
| Change | Before | After (v27 / JS SDK 13) | Who |
|---|---|---|---|
FunctionsError.message |
Exact server message string | Message plus a trailing [<httpStatus>] suffix (for example Invalid test requested. [400]) |
Web / macOS only |
FunctionsError.customData.url |
Not present | Request URL string on customData |
Web / macOS only |
Native iOS and Android continue to surface callable failures through the native bridge as HttpsError without the HTTP status suffix. Do not assume the suffix or customData.url on those platforms.
Migration actions
- Search for exact-equality checks on
error.message/e.messagefor callable failures. - On web/macOS, prefer
message.startsWith(expected)or strip a trailing[digits]before comparing. - If you need the HTTP status or request URL, read them from the suffix /
customData.urlon web/macOS only; keep a native fallback path for iOS/Android.
// Previously (exact match — breaks on web/macOS after 12.18.0)
if (e.message === 'Invalid test requested.') {
/* … */
}
// Now (tolerant of the optional " [status]" suffix)
const base = e.message.replace(/ \[\d+\]$/, '');
if (base === 'Invalid test requested.') {
/* … */
}
// Optional on Platform.other:
// e.customData?.urlUpstream note: [email protected] — “Add HTTP status code to the message field and add url to customData.”
Cloud Messaging
These changes correct runtime behavior to match the public RemoteMessage / listener contracts. There is no new public TypeScript surface — consumers that worked around the old accidental shapes must update.
String APNs sound → `notification.ios.sound`
PR: #9246
String-valued APNs sounds are serialized at the documented message.notification.ios.sound path. Previously, only string sounds were placed at the undocumented message.notification.sound path (critical-sound dictionaries already used the correct iOS nesting).
| Before (accidental) | After (documented) |
|---|---|
message.notification.sound (string) |
message.notification.ios.sound (string) |
// Previously
const sound = message.notification?.sound;
// Now
const sound = message.notification?.ios?.sound;iOS `sentTime` is epoch milliseconds
PR: #9247
On iOS, RemoteMessage.sentTime is a number of epoch milliseconds, matching Android and the public type. FCM supplies seconds (often as a string); native serialization converts those values to milliseconds.
| Before (iOS accidental) | After |
|---|---|
string epoch seconds (for example "1522880044") |
number epoch milliseconds (for example 1522880044000) |
Android behavior is unchanged. Remove parseInt / string comparisons that assumed seconds.
// Previously (iOS)
const sentMs = Number(message.sentTime) * 1000;
// Now (iOS and Android)
const sentMs = message.sentTime; // number, epoch msiOS badge is a string
PR: #9252
iOS aps.badge is serialized as a string, matching RemoteMessage.notification.ios.badge?: string.
| Before (iOS accidental) | After |
|---|---|
number (for example 7) |
string (for example "7") |
// Previously
const badge = message.notification?.ios?.badge; // number on iOS
// Now
const badge = Number(message.notification?.ios?.badge ?? 0);`onMessageSent` receives a string message ID
PR: #9254
onMessageSent listeners receive the documented message-ID string. Android previously forwarded the transport wrapper { messageId } to application code.
| Before (accidental) | After (documented) |
|---|---|
{ messageId: string } |
string |
// Previously
onMessageSent(messaging, ({ messageId }) => {
console.log(messageId);
});
// Now
onMessageSent(messaging, messageId => {
console.log(messageId);
});Removed Imagen API
This section covers only Imagen API removals. Other @react-native-firebase/ai breaking removals and renames (VertexAIBackend → AgentPlatformBackend, positional template generateContent → TemplateRequest, sendMedia* → realtime senders, and related fields) are listed in AI Logic breaking removals — that table remains authoritative for the rest of the AI Logic API breaks.
Imagen exports and generateImages are gone. Use getGenerativeModel() / getTemplateGenerativeModel() with a Gemini image model (responseModalities + imageConfig) instead.
Removed exports
{/* prettier-ignore */}
| Removed | Replacement |
|---|---|
getImagenModel |
getGenerativeModel() with a Gemini image model |
getTemplateImagenModel |
getTemplateGenerativeModel() with a template that uses an image model |
ImagenModel |
GenerativeModel |
TemplateImagenModel |
TemplateGenerativeModel |
ImagenModelParams |
ModelParams |
ImagenGenerationConfig |
GenerationConfig with responseModalities and imageConfig |
ImagenImageFormat |
No replacement — Gemini image models always return PNG; read inlineData.mimeType to confirm |
ImagenGenerationResponse |
GenerateContentResult |
ImagenInlineImage |
InlineDataPart on the response candidate |
ImagenGCSImage |
No replacement — Gemini image models return inline data |
ImagenAspectRatio |
ImageConfigAspectRatio |
ImagenSafetySettings |
SafetySetting[] on getGenerativeModel() |
ImagenSafetyFilterLevel |
HarmBlockThreshold |
ImagenPersonFilterLevel |
No replacement — Gemini image models allow generating people by default |
Example
// Previously (removed)
import { getApp } from '@react-native-firebase/app';
import { getAI, getImagenModel, ImagenAspectRatio } from '@react-native-firebase/ai';
const ai = getAI(getApp());
const imagenModel = getImagenModel(ai, {
model: 'imagen-3.0-generate-002',
generationConfig: {
aspectRatio: ImagenAspectRatio.LANDSCAPE_16x9,
},
});
const result = await imagenModel.generateImages('Draw a red bicycle on a beach at sunset');
console.log(result.images[0].mimeType);// Now
import { getApp } from '@react-native-firebase/app';
import {
getAI,
getGenerativeModel,
ImageConfigAspectRatio,
ImageConfigImageSize,
ResponseModality,
} from '@react-native-firebase/ai';
const ai = getAI(getApp());
const model = getGenerativeModel(ai, {
model: 'gemini-3.1-flash-image',
generationConfig: {
responseModalities: [ResponseModality.IMAGE],
imageConfig: {
aspectRatio: ImageConfigAspectRatio.LANDSCAPE_16x9,
imageSize: ImageConfigImageSize.SIZE_1K,
},
},
});
const result = await model.generateContent('Draw a red bicycle on a beach at sunset');
const imagePart = result.response.inlineDataParts()?.[0];
console.log(imagePart?.inlineData.mimeType);See AI Logic usage for more image generation examples, and Google's Imagen to Gemini migration guide for model and prompt guidance.
App (iOS)
PR: #9337
These changes landed with the App native Swift/Kotlin port. Most apps that only use the JavaScript API are unaffected by the header change; the data-collection fix can change runtime behavior if you passed automaticDataCollectionEnabled: false and previously still got collection enabled.
`automaticDataCollectionEnabled` is a boolean
initializeApp / native app options now read automaticDataCollectionEnabled as a boolean. Previously the Objective-C path cast the option value to a pointer, so any non-nil value — including JavaScript false — enabled automatic data collection.
| Value | Before (accidental) | After |
|---|---|---|
true |
enabled | enabled |
false / 0 / null / omit |
enabled if non-nil | disabled |
Migration actions
- Search for
automaticDataCollectionEnabledininitializeAppoptions and native config. - If you passed
falseexpecting collection to stay off, you are now correct — no change needed beyond verifying analytics/collection behavior. - If you relied on the old bug (passing a non-boolean non-nil value, or
falsewhile still seeing collection), set an explicit boolean for the behavior you want.
import { initializeApp } from '@react-native-firebase/app';
// Now false / null / absent disable collection; only true enables it.
await initializeApp({
// …
automaticDataCollectionEnabled: false,
});Public headers no longer import FirebaseCore / Photos
These public App headers no longer import FirebaseCore or Photos. Forward declarations are used instead. Downstream native code that compiled only because those headers pulled the frameworks in transitively must import them at the call site.
| Header | No longer imports |
|---|---|
RNFBSharedUtils.h |
FirebaseCore |
RCTConvert+FIRApp.h |
FirebaseCore |
RCTConvert+FIROptions.h |
FirebaseCore |
RNFBUtilsModule.h |
Photos |
Migration actions
- If a native
.m/.mm/.swiftfile fails to compile with unknownFIRApp/FIROptions/PHAsset(or similar) after upgrading, add the import next to your other Firebase / Photos imports. - JavaScript-only apps do not need changes for this item.
// Example — add at the call site if you used RNFB headers and relied on the old transitive import
#import <FirebaseCore/FirebaseCore.h>
#import <Photos/Photos.h>Removed ML package
@react-native-firebase/ml is removed in v27. The package had already been mostly discontinued: Firebase no longer ships the legacy ML APIs this module wrapped, and the React Native Firebase surface exposed no public APIs.
Migration actions
- Remove
@react-native-firebase/mlfrom your dependencies (yarn remove @react-native-firebase/mlor equivalent). - Delete any imports of
@react-native-firebase/ml(for examplegetML) — they no longer resolve. - For on-device ML Kit features, use Google ML Kit via the community react-native-mlkit modules.
- To call Cloud Vision from your app, prefer Firebase Authentication and Cloud Functions as a managed gateway. See the vision-annotate-images Functions sample.
Ecosystem compatibility tips
Third-party native modules and host toolchain pins sometimes need small adjustments when moving to BoM 35 / Firebase Apple 13. The supported Android path is Kotlin ≥ 2.4.0 (Platforms). The items below collect common ecosystem notes and unsupported workarounds — React Native Firebase does not ship these flags or property overrides for you.
Kotlin ≥ 2.4.0 (supported)
Firebase Android BoM 35 / firebase-auth 25 ships Kotlin 2.4.0 metadata. Raise the Kotlin Gradle plugin to ≥ 2.4.0 so the compiler can read that metadata. This is the supported path; see Platforms.
Unsupported older-Kotlin workaround
Unsupported. Prefer Kotlin ≥ 2.4.0. The
-Xskip-metadata-version-checkapproach below is not recommended, may break if your app or another module calls Firebase Auth Kotlin APIs, and React Native Firebase offers no support for failures that follow from it. React Native Firebase does not ship this compiler flag.
If you must stay on an older Kotlin compiler temporarily, add the flag on the auth module's KotlinCompile tasks from the app android/build.gradle (preferred over patching node_modules):
// android/build.gradle — UNSUPPORTED workaround; prefer Kotlin ≥ 2.4.0
subprojects { subproject ->
def n = subproject.name
if (n.contains('react-native-firebase_auth') || n.contains('@react-native-firebase_auth')) {
subproject.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions.freeCompilerArgs += ['-Xskip-metadata-version-check']
}
}
}Autolinking project names vary (react-native-firebase_auth, @react-native-firebase_auth). Adjust the name match if your Gradle project path differs. As a last resort you can drop an equivalent tasks.withType(...KotlinCompile) block into node_modules/@react-native-firebase/auth/android/build.gradle and persist it with patch-package — prefer the app-level subprojects pattern so you do not patch node_modules when avoidable.
AsyncStorage / KSP
@react-native-async-storage/async-storage 3.1.1 (and similar releases) may lack a KSP mapping for Kotlin 2.4.0. Until upstream maps 2.4.0, pin a known KSP in the app's android/gradle.properties:
AsyncStorage_kspVersion=2.3.12Other native modules that use KSP may need analogous overrides until their maintainers publish mappings for Kotlin 2.4.0.
Google Sign-In + Firebase 13 SPM
Google Sign-In alongside Firebase 13 can fail App Check resolution on SPM and
CocoaPods for different reasons. See
iOS SPM Support § Google Sign-In caveat
for current upstream status on each path.
Automated migration checklist
Use this section when running scripted or agent-assisted upgrades from v26 → v27.
1. Upgrade dependencies
# Bump all @react-native-firebase/* packages to v27 together (monorepo versions are aligned)
yarn add @react-native-firebase/app@^27.0.0 …
cd ios && pod installConfirm the lockfiles resolve firebase / firebase-js-sdk 13.0.0, Android BoM 35, and iOS SPM Firebase 13.0.0. Confirm Android minSdk 24 and macOS 11.0.
2. Agent-oriented search and replace
For each area you use, search the listed symbols and apply the replacements:
| Area | Search for | Replace with / action |
|---|---|---|
| Android floor | minSdkVersion / minSdk 23 (or lower) |
24 |
| Android Kotlin | kotlinVersion / Kotlin Gradle plugin below 2.4.0 |
≥ 2.4.0 (BoM 35 / firebase-auth 25 metadata) |
| iOS DisableSPM | $RNFirebaseDisableSPM, Expo disableSPM: true |
Remove; use SPM + use_frameworks! :linkage => :dynamic |
| Functions (web/macOS) | e.message ===, error.message === on callable failures |
Tolerate trailing [<digits>]; optionally read customData.url on Platform.other only |
| Messaging sound | notification.sound (string APNs sound) |
notification.ios.sound |
Messaging sentTime |
string/parseInt/* 1000 on sentTime (iOS) |
Use numeric epoch-ms directly |
| Messaging badge | numeric use of notification.ios.badge |
Parse string (Number(...)) when a number is required |
Messaging onMessageSent |
({ messageId }) / .messageId in the listener |
Use the string argument directly |
| AI backend | VertexAIBackend, BackendType.VERTEX_AI |
AgentPlatformBackend / AGENT_PLATFORM (document global default) |
| AI templates | positional generateContent(templateId, vars, …) |
generateContent({ templateId, templateVariables, toolConfig? }) |
| AI live media | sendMediaChunks, sendMediaStream |
sendTextRealtime / sendAudioRealtime / sendVideoRealtime |
| AI tokens | totalBillableCharacters |
totalTokens |
| AI Imagen | getImagenModel, getTemplateImagenModel, ImagenModel, Imagen*, generateImages |
getGenerativeModel / getTemplateGenerativeModel with responseModalities + imageConfig |
| App iOS data collection | automaticDataCollectionEnabled in initializeApp options |
Use an explicit boolean; false / 0 / null / absent now disable collection |
| App iOS native headers | compile errors for FIRApp / FIROptions / PHAsset after including RNFB headers |
#import <FirebaseCore/FirebaseCore.h> and/or #import at the call site |
| ML package | @react-native-firebase/ml, getML |
Remove the dependency; use react-native-mlkit or Cloud Vision via Functions (sample) |
3. Validate
yarn compile
# TypeScript consumers: fix compile errors from removed Imagen exports and messaging types
# Manually exercise: callable error message handling (web/macOS), FCM notification fields (iOS), onMessageSent, Gemini image generation
# Native iOS: rebuild any pods/apps that import RNFB App headers; confirm automaticDataCollectionEnabled false disables collectionRelated PRs (v27 breaking changes)
| Area | PR |
|---|---|
Firebase JS SDK 12.18.0 / FunctionsError |
#9218 |
| Messaging — APNs string sound path | #9246 |
Messaging — iOS sentTime epoch-ms |
#9247 |
| Messaging — iOS badge string | #9252 |
Messaging — onMessageSent string ID |
#9254 |
| AI — Imagen API removal | #9275 |
| App iOS — ADC boolean + header imports | #9337 |
| SDK majors (Android 35 / Apple 13 / JS 13), ML removal, AI Logic JS 13 | #9372 |
Migrating To V6 (`docs/migrating-to-v6.mdx`)
title: Migrating to v6 previous: /vertexai/usage
Introduction
This is a reference for upgrading from React Native Firebase v5.x.x to v6.x.x. Even though there is a lot to cover,
each module generally follows similar steps to migrate.
We highly recommend your project is using React Native 0.60+ before upgrading to take advantage of new features to make
the migration process much simpler.
We highly recommend backing up your project before migrating!
If you're looking to start fresh, check out the Getting Started section of the documentation.
Why you should migrate
React Native Firebase version 6 has been re-created from the ground up, with a heavy focus on testing, documentation & feature
compatibility with the Firebase SDKs. We've also been working closely with the Firebase team to ensure all module APIs have
been approved before being released.
We have also ensured the release is compatible with some of the popular tooling in the React Native community, such as
autolinking & TypeScript.
Version 6 also brings support for previously unsupported modules such as Firebase ML.
NPM dependency changes
Prior to version 6, all modules are installable from the react-native-firebase NPM package. With version 6 we are
now taking advantage of NPM organizations, allowing us to distribute each module as its own package. This has a number
of advantages such as smaller app bundle sizes (you only install what modules you need), and internally we treat each module
as its own package, allowing for easier testing and quality assurance. Every project must install the @react-native-firebase/app
module, replacing the react-native-firebase module.
Removing `react-native-firebase`
There are a number of steps to carry out to remove the react-native-firebase module from your existing app. To help make this process
easier, we'll break out the process into 3 sections:
Removing v5 from JavaScript
As mentioned above, we need to remove the react-native-firebase NPM module from our project. To do this, open your projectspackage.json file and remove the dependency:
{
"dependencies": {
"react": "16.8.3",
"react-native": "0.59.9",
- "react-native-firebase": "^5.5.4"
}
}To remove the package from your local environment, delete the yarn.lock/package-lock.json files and reinstall
the project dependencies with yarn.
Removing v5 from Android
Removing version 5 from your native Android code is a more involved process. We'll go file by file to ensure all references
to the older version have been removed.
Removing from Gradle Settings
Open up your projects /android/settings.gradle file. There will be 2 lines which need to be removed:
rootProject.name = 'AwesomeApp'
- include ':react-native-firebase'
- project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
include ':app'Removing from Android Manifest
Open your AndroidManifest.xml file. You will need to remove any references to the io.invertase.firebase.messaging class
- <service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
- <intent-filter>
- <action android:name="com.google.firebase.MESSAGING_EVENT" />
- </intent-filter>
- </service>Removing native dependencies
We now need to remove the RNFirebase and Firebase dependencies from your project.
In version 6, these are automatically installed for us.
Open your projects /android/app/build.gradle file. First remove the react-native-firebase dependency:
dependencies {
- implementation project(path: ':react-native-firebase')
}Next, remove the firebase-core and play-services-base dependencies. Note, other modules you are using may
required play-services-base to be installed.
Specific versions listed may be different than your own project
dependencies {
- implementation "com.google.firebase:firebase-core:16.0.9"
- implementation "com.google.android.gms:play-services-base:16.1.0"
}Next we need to remove the module specific Firebase dependencies. The naming convention for these modules is:implementation "com.google.firebase:firebase-<< module >>:<<version>>".
For example, to remove the native Firebase dependency for the Authentication module:
dependencies {
- implementation "com.google.firebase:firebase-auth:17.0.0"
}Removing the React Native Firebase packages
We now need to remove the React Native Firebase packages from being added to our React Native application. Go ahead and open
the /android/app/src/main/java/<< app name >>/MainApplication.java file.
First, we need to remove the core RNFirebasePackage from the imports and being added to the package list:
- import io.invertase.firebase.RNFirebasePackage;@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
- new RNFirebasePackage(),Depending on what modules you installed using version 5, remove the packages for each module. For example, to remove the
Authentication package:
- import io.invertase.firebase.auth.RNFirebaseAuthPackage;@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
- new RNFirebaseAuthPackage(),Cleaning Gradle
Android caches module dependencies for quicker builds. As we've heavily modified our project dependencies it's recommended you
clean Gradle, allowing for a fresh installation. In your project, execute the following commands:
$ cd android/
$ ./gradlew cleanRemoving v5 from iOS
The following steps assume you have used CocoaPods to manage your projects iOS dependencies.
Remove the RNFirebase Pod
Remove the RNFirebase pod from your /ios/Podfile:
target 'AwesomeApp' do
- pod 'RNFirebase', :path => '../node_modules/react-native-firebase/ios'Remove the Firebase Core Pod
The Firebase/Core need to be removed from the project. In version 6, this is automatically installed. Open the/ios/Podfile and remove the Pod:
target 'AwesomeApp' do
- pod 'Firebase/Core', '~> 6.3.0'Remove module specific Pods
Depending on what modules you were using with version 5, we now need to remove the Firebase Pods. For example, if you
are using the Authentication module, remove the Firebase/Auth Pod:
target 'AwesomeApp' do
- pod 'Firebase/Auth', '~> 6.3.0'Re-installing Pods
Once the Pod dependencies have been removed, the following commands will remove the Pods from your local project:
$ cd ios
$ rm -rf Podfile.lock
$ pod installInstalling `@react-native-firebase/app`
As mentioned earlier, version 6 uses the @react-native-firebase NPM organization for each module. Every app using
version 6 must install the app module before installing each specific module.
To get started, install the new dependency with Yarn:
yarn add @react-native-firebase/appIf you are using React Native 0.60+, the module will be automatically linked via autolinking.
Users on an older version of React Native must manually link the app module. See the following steps for Android and
iOS for more information on manual linking.
Specific module installation
Depending on which Firebase service your app uses, you now need to install the NPM packages for each service. For example,
apps using the Authentication module need to install the auth package:
yarn add @react-native-firebase/authInstall the modules required for your application:
| Module | NPM Package |
|---|---|
| @react-native-firebase/admob | |
| @react-native-firebase/analytics | |
| @react-native-firebase/app | |
| @react-native-firebase/invites | |
| @react-native-firebase/auth | |
| @react-native-firebase/firestore | |
| @react-native-firebase/functions | |
| @react-native-firebase/messaging | |
| @react-native-firebase/storage | |
| @react-native-firebase/crashlytics | |
| @react-native-firebase/in-app-messaging | |
| @react-native-firebase/iid | |
| @react-native-firebase/ml | |
| @react-native-firebase/perf | |
| @react-native-firebase/database | |
| @react-native-firebase/remote-config |
Users on React Native version 0.60+, the modules will be automatically linked. For users on a lower version,
see the module specific pages for manual installation guides.
Updating project code
In versions prior to 6, accessing the React Native Firebase package was carried out by importing the react-native-firebase
module, for example:
import firebase from 'react-native-firebase';
// App code...
const user = firebase.auth().currentUser;Although it is possible to access specific module functionality from the package imports, if you're coming from v5 the
following usage may seem daunting for a large project:
import auth from '@react-native-firebase/auth';
// App code...
const user = auth().currentUser;Fortunately, it is possible to continue to migrate to the previous versions import method:
Find and replace all usages of the import with the new import:
- import firebase from 'react-native-firebase';
+ import firebase from '@react-native-firebase/app';We now need to import additional packages inside of an entry point file of our project, for example
to import the Authentication module, add the following to your projects /App.js file (or entry file):
import firebase from '@react-native-firebase/app';
import '@react-native-firebase/auth';
// App code
const user = firebase.auth().currentUser;This only needs to be done once. The auth module will now be available on all firebase instances.
Module Breaking Changes
Below outlines a list of breaking changes for each module which may impact your application. Please ensure all
app functionality is tested once migrated to version 6 is complete.
App
@react-native-firebase/app
onReady()removed: Users initializing a secondary app viaapp.initializeAppwill need to now remove theonReady
listener. Instead,initializeAppresolves a promise once the secondary app has finished initializing.- Initializing the
[DEFAULT]app manually will now throw an error. Previously this only displayed a warning.
AdMob
@react-native-firebase/admob
The AdMob module has undergone a full re-write to support a new, cleaner API and regulation changes (such as GDPR).
Please see the
RewardedVideohas now been deprecated in favor of a new native API. Please seeRewardedAdfor more information.
Invites
The invites module has now been deprecated. Please see the official Firebase Dynamic Links deprecation FAQ
for more information.
The recommended approach for handling this deprecation is to use the Dynamic Links module.
Analytics
@react-native-firebase/analytics
- All methods now return a
Promise. Previously these were 'fire and forget'.
Crashlytics
@react-native-firebase/crashlytics
setBoolValue,setFloatValue,setIntValue&setStringValuehave been removed and replaced with two new methods (the Crashlytics SDK converted all these into strings internally anyway):setAttribute(key: string, value: string): Promise<null>- set a singular key value to show alongside any subsequent crash reportssetAttributes(values: { [key: string]: string }): Promise<null>- set multiple key values to show alongside any subsequent crash reports
- All methods except
crash,log&recordErrornow return a Promise that resolve when complete. recordErrornow accepts a JavaScriptErrorinstead of a code and message.setUserIdentifier()has been renamed tosetUserId()to match the Analytics Web SDK implementation.enableCrashlyticsCollection()has been renamed tosetCrashlyticsCollectionEnabled().
Firestore
@react-native-firebase/firestore
- The
Blobclass can no longer be manually constructed. - All user code is now validated in
JavaScript. Passing incorrect data or querying chaining will now throw a JavaScript error. Ensure all queries are thoroughly tested.- The
Queryclass has undergone a rewrite. Previously some invalid queries could be passed to the native SDKs causing a crash, these are now validated in JavaScript.
- The
- The where equal operator
=has been deprecated. Please use==. - The setting
setTimestampsInSnapshotsEnabledhas been deprecated.
Dynamic Links
@react-native-firebase/dynamic-links
- Module usage has been renamed from
links()todynamicLinks(). - The
onLinkandgetInitialLinkmethods now return aDynamicLinkobject, rather than the string URL. - The builder syntax has been deprecated in favor of simple objects. See
buildLink()documentation for an example. - Added extra validation. Building a dynamic link with platform specific options will now error if not all required parameters are set.
Functions
@react-native-firebase/functions
No breaking changes.
In-App Messaging
@react-native-firebase/in-app-messaging
This is a new module. See documentation for usage.
Instance ID
@react-native-firebase/iid
No breaking changes.
Notifications
Device-local notification APIs are not actually Firebase APIs at the same time they are very difficult to maintain.
For these reasons the notifications package has been removed from react-native-firebase for versions 6 and higher.
How to migrate: If you use device-local notification APIs and user-visible notifications in your app you will want to integrate a separate library that gives you access to device-local notification APIs. Many people have reported success with each of https://notifee.app, https://wix.github.io/react-native-notifications and https://github.com/zo0r/react-native-push-notification
Cloud Messaging
@react-native-firebase/messaging
- [android] The manually added
RNFirebaseMessagingServiceservice in yourAndroidManifest.xmlfile is no longer required - you can safely remove it. - [iOS] The manually added
RNFirebaseMessagingusages in yourAppDelegatefiles are no longer required - you can safely remove them. - The builder syntax has been deprecated in favor of simple objects. See
newRemoteMessage()documentation for an example. subscribeToTopic('some-topic')method must not include "/" in topic.- [iOS] The minimum supported iOS version is now 10
- iOS 9 or lower only accounts for 0.% of all iPhone devices.
- To see a detailed device versions breakdown see this link.
- Community contributions that add iOS 9 support are welcome.
Performance Monitoring
@react-native-firebase/perf
- All
Trace&HttpMetricmethods (except forstart&stop) are now synchronous and no longer return a Promise,
extra attributes/metrics now only get sent to native when you call stop. firebase.perf.Trace.incrementMetricwill now create a metric if it could not be found.firebase.perf.Trace.getMetricwill now return 0 if a metric could not be found.
Realtime Database
@react-native-firebase/database
- The
Referenceclass has undergone a rewrite. In previous versions, chaining invalid methods together on a query was possible. In version 6, the functionality now replicates the Firebase Web SDK.- Please thoroughly test your database queries.
- Internal JavaScript validation has been added and will throw a JavaScript error if methods are called with incorrect parameters.
- All query based modifiers are now validated as per the Web SDK spec. In v5 it is possible to chain queries which are not allowed together causing native errors (e.g.
.orderByKey().orderByPriority(),.startAt('foo', 'bar').orderByKey()etc). Doing so in v6 will now throw an error to keep it in-line with the Web SDK. Reference.pushnow correctly mimics the Web SDK, returning a thenable reference.
Remote Config
@react-native-firebase/remote-config
- Module namespace has been renamed to
.remoteConfig()from.config(). - All Remote Config values can now be accessed synchronously in JS, see
getValue(key: string): ConfigValue&getAll(): ConfigValuesbelow.- These replace all the original async methods:
getValue,getValues,getKeysByPrefix.
- These replace all the original async methods:
setDefaultsFromResourcenow returns a Promise that resolves when completed, this will reject with codeconfig/resource_not_foundif the file could not be found.setDefaultsFromResourcenow expects a resource file name for Android to match iOS, formerly this required a resource id (something you would not have in RN as this was generated at build time by Android).- An example for both platforms can be found in the tests.
enableDeveloperModehas been removed, you can now usesetConfigSettings({ isDeveloperModeEnabled: boolean })instead.setDefaultsnow returns a Promise that resolves when completed.
Cloud Storage
@react-native-firebase/storage
- Removed formerly deprecated
UploadTaskSnapshot.downloadUrlproperty, useStorageReference.getDownloadURL(): Promise<string>instead. StorageReference.downloadFile()is now deprecated and will be removed in a later release, please rename usages of this towriteToFile()- renamed to match Native SDKs.firebase.storage.Nativehas moved tofirebase.utils.Native.firebase.utils.Nativeis now deprecated and will be removed in a later release, please rename usages of this tofirebase.utils.FilePath.firebase.utils.Native.*some properties have been renamed and deprecated and will be removed in a later release, follow the in-app console warnings on how to migrate.
ML
@react-native-firebase/ml
This is a new module. See documentation for usage.
Platforms (`docs/platforms.mdx`)
title: Platforms previous: /typescript next: /ios-spm
Status
By default React Native Firebase supports multiple platforms using the native Firebase SDK for the specific platform:
| Platform | Minimum Version |
|---|---|
| Android | 7.0 (API 24 / Nougat) |
| iOS | 15.0 |
| macOS | 11.0 |
Important - To compile your application for Android, you will need a minimum JDK (Java Development Kit) version of >= 17, and a Kotlin Gradle plugin of >= 2.4.0 (Firebase Android BoM 35 / firebase-auth 25 ships Kotlin 2.4.0 metadata). For ecosystem workarounds (unsupported older Kotlin, AsyncStorage KSP, Google Sign-In), see Migrating to v27 § Ecosystem compatibility tips.
However, for platforms that we don't provide a Native Module for, React Native Firebase instead implements a fallback Firebase JS SDK implementation to support
these 'Other' platforms, e.g.;
- Web
- macOS
- Windows
- ...and any other RN based environment.
Below is a table outlining which Firebase modules are supported on each platform in React Native Firebase:
| Firebase Service | Android | iOS | Other |
|---|---|---|---|
| ai | ✅ | ✅ | ✅ |
| analytics | ✅ | ✅ | ✅ |
| app | ✅ | ✅ | ✅ |
| app-check | ⚠️ | ⚠️ | ⚠️ |
| app-distribution | ✅ | ✅ | ❌ |
| auth | ✅ | ✅ | ⚠️ |
| crashlytics | ✅ | ✅ | ❌ |
| database | ✅ | ✅ | ✅ |
| firestore | ✅ | ✅ | ⚠️ |
| functions | ✅ | ✅ | ✅ |
| in-app-messaging | ✅ | ✅ | ❌ |
| installations | ✅ | ✅ | ❌ |
| messaging | ✅ | ✅ | ❌ |
| perf | ✅ | ✅ | ❌ |
| phone-number-verification | ✅ | ❌ | ❌ |
| remote-config | ✅ | ✅ | ✅ |
| storage | ✅ | ✅ | ⚠️ |
- ✅ (supported)
- ⚠️ (partial support) - see notes below
- ❌ (not supported)
Other Platforms
Whenever the React Native Firebase SDK is running on platforms other than Android
or iOS, the internal implementation uses a fallback platform which is implemented
in JavaScript, using the Firebase JavaScript Modular SDK.
No implementation changes are required to use the React Native Firebase SDK on
other platforms (with the exception of Async Storage detailed below), as the
JavaScript implementation is automatically used when a native platform is not
available. This allows you to use the same API across all platforms, regardless
of the underlying implementation.
There are however some minor limitations or differences in behavior compared
to the native platforms. Where a particular method is not supported, an error
will be thrown with a code of unsupported to indicate the method is not
available on the current platform.
Further details of Firebase service specific limitations are summarized below.
Async Storage
Some services (currently Auth and Analytics) for our 'Other' platforms
implementation require a Async Storage implementation to be provided to
enable persistence, React Native Firebase provides an API to set this implementation:
import { initializeApp, setReactNativeAsyncStorage } from '@react-native-firebase/app';
import AsyncStorage from '@react-native-async-storage/async-storage';
setReactNativeAsyncStorage(AsyncStorage);
await initializeApp({ ... });Note: we use
@react-native-async-storage/async-storageas an example, you should use the Async Storage implementation that is appropriate for your platform that you are targeting.
If you do not provide an Async Storage implementation, we use an in memory implementation
which will result in resetting the data every time your app is restarted, in the case of
Firebase Auth this means your users have to sign in again and for Firebase Analytics the app will generate a new instance id and look like a new installation every time.
Analytics
The other platform implementation of Analytics does not capture automatic metrics like screen view, you must call logEvent and other logging based methods to send your events to Firebase.
App Check
App Check for other platforms only supports the CustomProvider provider. Here's how to setup your own custom provider:
- Implement server support to get tokens
- Create a custom provider in your app:
import { getApp } from '@react-native-firebase/app';
import { CustomProvider, initializeAppCheck } from '@react-native-firebase/app-check';
const myCustomProvider = new CustomProvider({
async getToken: () => {
const tokenFromServer = 'some-token-from-server';
const expirationFromServer = 1000 * 60 * 60;
const appCheckToken = {
token: tokenFromServer,
expireTimeMillis: expirationFromServer * 1000
};
return appCheckToken;
}
});
await initializeAppCheck(getApp(), {
provider: myCustomProvider
});Authentication
Multi-factor authentication is not supported on other platforms.
Phone authentication methods are unsupported, specifically:
signInWithProvidersignInWithPhoneNumberverifyPhoneNumberForMultiFactorconfirmationResultConfirmverifyPhoneNumberreauthenticateWithProvider
Database
Offline persistence is not supported on other platforms.
Unsupported methods:
keepSynced- for offline persistence
Firestore
For performance reasons and to reduce the size of the JavaScript bundle, the Other platform implementation in
React Native Firebase uses the JavaScript lite SDK,
which does not support methods related to offline & persistence.
Specifically, the following methods are not supported:
loadBundleclearPersistence- for offline persistencedisableNetwork- for offline persistenceenableNetwork- for offline persistencenamedQueryonSnapshot(for bothCollectionReference&DocumentReference)GetOptions.source
Storage
No-op methods:
setMaxDownloadRetryTime(does not throw, but has no effect)
Unsupported methods:
writeToFileputFile
Known Issues
Known issues will be documented here and updated regularly.
- There are currently no known issues.
Typescript (`docs/typescript.mdx`)
title: TypeScript next: /platforms previous: /migrating-to-v27
React Native Firebase ships TypeScript declarations for every module. From v25 onward, modular types and helpers are exported from each package root (for example @react-native-firebase/auth) alongside the namespaced default export.
If you are setting up TypeScript in a new React Native app, see the official TypeScript documentation.
Modular API
Import modular helpers and types from the package root:
import { useEffect, useState } from 'react';
import { getAuth, onAuthStateChanged, type User } from '@react-native-firebase/auth';
function App() {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
const authInstance = getAuth();
return onAuthStateChanged(authInstance, setUser);
}, []);
if (!user) {
return null;
}
return user.email;
}See Migrating to v25 for Auth breaking changes (FirebaseAuthTypes deprecation, provider helpers, async isSignInWithEmailLink, and other firebase-js-sdk alignment updates).
Where definitions live
Published types are built to packages/<module>/dist/typescript/ (for example packages/auth/dist/typescript/lib/index.d.ts). Source lives under packages/<module>/lib/ as TypeScript (.ts) since the v25 package migrations.
Modular Auth source: packages/auth/lib/index.ts.
Public API reference (generated from source JSDoc): reference API.
Definitions per module
Each package exports its own types from the package root. Examples:
| Module | Modular types (import from package root) |
|---|---|
| Auth | User, Auth, UserCredential, OAuthProvider, … |
| Firestore | FirebaseFirestoreTypes namespace (namespaced) + modular helpers from @react-native-firebase/firestore |
| App Check | AppCheck, AppCheckTokenResult, … |
For Auth v25 alignment details and intentional firebase-js-sdk differences, see the Auth compare:types triage knowledge document and yarn compare:types auth registry.
Analytics Screen Tracking (`docs/analytics/screen-tracking.mdx`)
title: Screen Tracking previous: /analytics/usage next: /app-check/usage
Standard React Native applications run inside a single Activity/ViewController, meaning any screen changes won't be
tracked by the native Firebase SDKs. There are a number of ways to implement navigation within React Native apps,
therefore there is no "one fits all" solution to screen tracking.
React Navigation
The React Navigation library allows for various navigation techniques such as
Stack, Tab, Native or even custom navigation. The NavigationContainer component which the library exposes provides
access to the current navigation state when a screen changes, allowing you to use the logScreenView
method the Analytics library provides:
import { getAnalytics, logScreenView } from '@react-native-firebase/analytics';
import { NavigationContainer } from '@react-navigation/native';
const App = () => {
const routeNameRef = React.useRef();
const navigationRef = React.useRef();
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
routeNameRef.current = navigationRef.current.getCurrentRoute().name;
}}
onStateChange={async () => {
const previousRouteName = routeNameRef.current;
const currentRouteName = navigationRef.current.getCurrentRoute().name;
if (previousRouteName !== currentRouteName) {
await logScreenView(getAnalytics(), {
screen_name: currentRouteName,
screen_class: currentRouteName,
});
}
routeNameRef.current = currentRouteName;
}}
>
...
</NavigationContainer>
);
};
export default App;For a full working example, view the Screen tracking for analytics
documentation on the React Navigation website.
React Native Navigation
The wix/react-native-navigation provides 100% native platform navigation
for React Native apps. To manually track screens, you need to setup a componentDidAppear event listener and manually call thelogScreenView method the Analytics library provides:
import { getAnalytics, logScreenView } from '@react-native-firebase/analytics';
import { Navigation } from 'react-native-navigation';
Navigation.events().registerComponentDidAppearListener(async ({ componentName, componentType }) => {
if (componentType === 'Component') {
await logScreenView(getAnalytics(), {
screen_name: componentName,
screen_class: componentName,
});
}
});To learn more, view the events documentation
on the React Native Navigation website.
App Json Config (`docs/app/json-config.mdx`)
title: Firebase JSON Config next: /app/utils previous: /app/usage
You can configure your installed modules by creating a file named firebase.json at the root of your project directory.
An example configuration file is available for inspection in our internal test app: <repo>/tests/firebase.json
JSON Schema
Add the Config Schema to your firebase.json file to use the Editor Intellisense
{
"$schema": "./node_modules/@react-native-firebase/app/firebase-schema.json"
}App Usage (`docs/app/usage.mdx`)
title: Core/App next: /app/json-config previous: /storage/usage
The App module is available by default once you have installed the React Native Firebase library by following the
Getting Started documentation. The App module currently provides the following functionality:
- Creating Secondary Firebase App Instances.
- Exposing Utilities to aid development.
Platform support and New Architecture
| Platforms | Android, iOS (native Firebase SDK) |
| New Architecture | Required from v26. See Migrating to v26. |
Platform notes: initializeApp is async on React Native (native bridge). registerVersion is web only and throws on native platforms.
Secondary Apps
Unlike the Firebase Web SDK, there is no need to manually call the initializeApp
method with your project credentials. The native Android & iOS SDKs automatically connect to your Firebase project using
the credentials provided during the Getting Started installation steps. The app module does however provide support
for manually initializing secondary Firebase app instances.
Currently, the native Firebase SDKs only provide functionality for creating secondary apps on the following services:
- App Check.
- Authentication.
- Realtime Database.
- Cloud Firestore.
- Cloud Functions.
- Cloud Storage.
- Installations.
- Remote Config.
Initializing secondary apps
The module exposes an initializeApp method which accepts arguments containing the credentials and options for your secondary
apps:
import { initializeApp } from '@react-native-firebase/app';
// Your secondary Firebase project credentials...
const credentials = {
clientId: '',
appId: '',
apiKey: '',
databaseURL: '',
storageBucket: '',
messagingSenderId: '',
projectId: '',
};
const config = {
name: 'SECONDARY_APP',
};
await initializeApp(credentials, config);Note that if you use multiple platforms, you will need to use the credentials relevant to that platform:
import { initializeApp } from '@react-native-firebase/app';
import { Platform } from 'react-native';
// Your secondary Firebase project credentials for Android...
const androidCredentials = {
clientId: '',
appId: '',
apiKey: '',
databaseURL: '',
storageBucket: '',
messagingSenderId: '',
projectId: '',
};
// Your secondary Firebase project credentials for iOS...
const iosCredentials = {
clientId: '',
appId: '',
apiKey: '',
databaseURL: '',
storageBucket: '',
messagingSenderId: '',
projectId: '',
};
// Select the relevant credentials
const credentials = Platform.select({
android: androidCredentials,
ios: iosCredentials,
});
const config = {
name: 'SECONDARY_APP',
};
await initializeApp(credentials, config);Once created, you can confirm the app instance has been created by accessing the apps property on the module:
import { getApps } from '@react-native-firebase/app';
const apps = getApps();
apps.forEach(app => {
console.log('App name: ', app.name);
});Switching app instance
You can switch app instances at any time whilst developing by calling the app method with the name of the secondary app:
import { getApp } from '@react-native-firebase/app';
import { getAuth } from '@react-native-firebase/auth';
getAuth(getApp('SECONDARY_APP')).currentUser;Or pass the secondary app instance you created above directly to the desired module, for example:
import { getApp, initializeApp } from '@react-native-firebase/app';
import { getAuth } from '@react-native-firebase/auth';
const secondaryApp = await initializeApp(credentials, config);
getAuth(secondaryApp).currentUser;Deleting instances
You can delete any secondary instances by calling the delete method on the instance:
await getApp('SECONDARY_APP').delete();App Utils (`docs/app/utils.mdx`)
title: Utils next: /crashlytics/usage previous: /app/json-config
The App module also provides access to some handy utility methods which have been exposed to aid with your
development.
File Paths
When working with modules such as Cloud Storage, you may need to know about the devices
current directory paths. Rather than installing a separate module, the library provides useful statics
which can be used.
Import FilePath directly from the app package:
import { FilePath } from '@react-native-firebase/app';
console.log(FilePath.PICTURES_DIRECTORY);Test Lab
Firebase TestLab
is a cloud-based app-testing infrastructure. With one operation, you can test your Android or iOS app across
a wide variety of devices and device configurations, and see the results—including logs, videos,
and screenshots—in the Firebase console.
It is useful to change the apps configuration if it is being run in Test Lab, for example disabling Analytics
data collection. Such functionality can be carried out by taking advantage of the isRunningInTestLab.
Be aware,
isRunningInTestLabis Android only property!
import { getUtils } from '@react-native-firebase/app';
import { getAnalytics, setAnalyticsCollectionEnabled } from '@react-native-firebase/analytics';
async function bootstrap() {
if (getUtils().isRunningInTestLab) {
await setAnalyticsCollectionEnabled(getAnalytics(), false);
}
}App Version
appVersion returns the host app's marketing version string: Android versionName or iOSCFBundleShortVersionString. Use it when you need the installed app version without pulling in a
separate package.
Be aware,
appVersionis available on Android and iOS only. On web and other non-native platforms
it isundefined(including when the native value is empty).
import { getUtils } from '@react-native-firebase/app';
const version = getUtils().appVersion;
if (version) {
console.log('App version:', version);
}Android - Checking Play Services
It is useful to know if the Android device has play services available, and what to do in response to certain use cases:
/* Detailed source-code truncated for AI context efficiency. */Auth Email Link Auth (`docs/auth/email-link-auth.mdx`)
title: Email Link Authentication next: /auth/oidc-auth previous: /auth/phone-auth
Email link (passwordless) authentication sends the user a one-time sign-in link. Opening that link on a device completes
sign-in and verifies ownership of the email address — no password required.
Firebase Auth no longer relies on Firebase Dynamic Links for this
flow. Mobile apps complete sign-in through Android App Links and iOS Universal Links on a domain you control
(often a Firebase Hosting domain). Official platform guides:
This page focuses on wiring the flow in React Native Firebase. It starts with the same default Hosting-domain path as the
official Android and Apple guides. There is information on optionally adding custom domains and branded landing pages later.
How the pieces fit together
| Piece | Role |
|---|---|
Continue URL (ActionCodeSettings.url) |
HTTPS URL embedded in the email. Its domain must be an Authorized domain in the Firebase Console. |
| Hosting link domain | Domain Firebase uses for the mobile Auth link (default PROJECT_ID.firebaseapp.com, or a custom Hosting / linkDomain). |
| Association files | /.well-known/assetlinks.json (Android) and /.well-known/apple-app-site-association (iOS) so the OS opens your app. |
| Native app config | Android intent-filter + SHA certificates; iOS Associated Domains + Linking handlers. |
| JS Auth APIs | sendSignInLinkToEmail → store email → isSignInWithEmailLink → signInWithEmailLink. |
handleCodeInApp must be true for email-link sign-in. Do not set deprecated dynamicLinkDomain. Prefer omittinglinkDomain unless you have configured a custom Hosting link domain for the project — Auth selects the project default
Hosting domain when it is omitted. Setting linkDomain to a bare *.web.app / *.firebaseapp.com default is often rejected.
Migrate from Dynamic Links
If the project previously used Firebase Dynamic Links for email sign-in, run the Admin SDK project-config update from the
Android migration guide so Auth issues Hosting mobile
links instead of FDL:
import { getAuth } from 'firebase-admin/auth';
await getAuth()
.projectConfigManager()
.updateProjectConfig({
mobileLinksConfig: {
// Literal value from the Firebase migration docs — switches the project
// from Dynamic Links to Firebase Hosting mobile links.
domain: 'HOSTING_DOMAIN',
},
});If emails still contain *.page.link after this, the project is still using Firebase Dynamic Links. linkDomain in ActionCodeSettings is only
for a custom Hosting domain — it does not perform this migration switch. Omitting deprecated dynamicLinkDomain is
required; see Troubleshooting if you still see DYNAMIC_LINK_NOT_ACTIVATED.
Choose a hosting path
You need a domain that can receive /__/auth/links (App Links / Universal Links). Pick the simplest path that matches your
app:
| Situation | Use |
|---|---|
| Getting started (no custom domain) | Use the project's default Hosting domain PROJECT_ID.firebaseapp.com. Register Android SHA-1 + SHA-256 in Firebase project settings so Firebase can serve association files. |
| Custom / branded domain | Attach a custom domain in Firebase Hosting (or reuse a domain you already operate). Serve /.well-known/assetlinks.json and /.well-known/apple-app-site-association on that host. Set linkDomain in ActionCodeSettings to that custom domain. |
Both paths end the same way: Authorized domain in Firebase Auth, association files available on the Hosting link domain, and
the React Native app claiming that domain via App Links / Universal Links.
Association files (custom domain only)
On the default PROJECT_ID.firebaseapp.com path, Firebase serves association files after SHA fingerprints are
registered — no separate generator required.
For a custom domain, publish these at the Hosting / custom domain (inline JSON, not a file download):
https://YOUR_DOMAIN/.well-known/assetlinks.jsonhttps://YOUR_DOMAIN/.well-known/apple-app-site-association
assetlinks.json needs package_name + SHA-256 fingerprints (Digital Asset Links).
AASA needs your Apple Team ID + bundle ID and paths covering /__/auth/links*
(Supporting associated domains). Serve both
with Content-Type: application/json and no attachment disposition.
Community generators exist for these JSON files; they are optional and unofficial — see
Optional community helpers at the end of this page.
Firebase Console setup
- Enable Email/Password, then enable Email link (passwordless sign-in) under
Authentication → Sign-in method. - Add your continue-URL host under Authentication → Settings → Authorized domains.
- Android: in Project settings, register the app's package name plus SHA-1 and SHA-256 certificate fingerprints
(required for App Links verification on the default Hosting domain). - iOS: ensure the bundle ID in the Firebase iOS app matches Xcode / Associated Domains.
Native app setup
Two domains are involved — confusing them is a common reason the link opens Safari or Chrome instead of the app:
- Hosting link domain (must match Associated Domains /
autoVerifyintent-filter):https://PROJECT_ID.firebaseapp.com/__/auth/links?...
— this is the URL the OS must open in the app. - Continue URL (
ActionCodeSettings.url): any authorized HTTPS URL; used when the app is not installed and as embedded
state. It does not have to be the same host as (1).
Claim the Hosting link domain in native config — typically PROJECT_ID.firebaseapp.com. Add PROJECT_ID.web.app or a
custom Hosting domain only if your project uses that host for Auth links.
Android
Add an autoVerify intent-filter on the activity that should receive the link (launchMode="singleTask" is typical so a
cold/warm start reuses one activity). Prefer separate <data> tags for scheme, host, and path — Android merges siblings.
See the upstream Android intent-filter.
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="YOUR_PROJECT_ID.firebaseapp.com" />
<data android:pathPrefix="/__/auth/links" />
</intent-filter>If you use a custom Hosting link domain, add another <data android:host="…" /> for that host. If your branded continue URL
is the site root (or other paths), add another filter (or additional path rules) for those hosts.
After install, verify App Links with:
adb shell pm get-app-links YOUR.PACKAGE.NAME
# optional force re-verify
adb shell pm verify-app-links --re-verify YOUR.PACKAGE.NAMEiOS
Enable the Associated Domains capability and add
applinks:YOUR_PROJECT_ID.firebaseapp.com. Addapplinks:YOUR_PROJECT_ID.web.app
or your custom Hosting domain only if Auth links use that host.Forward Universal Links and custom URLs to React Native
Linking(React Native'sRCTLinkingManager), for example inAppDelegate:
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
return RCTLinkingManager.application(
application,
continue: userActivity,
restorationHandler: restorationHandler
)
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return RCTLinkingManager.application(app, open: url, options: options)
}On a Mac with Apple's Shared Web Credentials tooling you can sanity-check AASA matching:
sudo swcutil verify -d YOUR_DOMAIN -j ./apple-app-site-association -u https://YOUR_DOMAIN/__/auth/linksExpo Setup
Email-link auth needs native App Links / Universal Links, so a development build
is required (Expo Go cannot claim applinks:).
In app.json / app.config.js:
- iOS:
expo.ios.associatedDomains:["applinks:YOUR_PROJECT_ID.firebaseapp.com"] - Android: an
intentFiltersentry withautoVerify: true,https, hostYOUR_PROJECT_ID.firebaseapp.com,pathPrefix/__/auth/links - Keep
@react-native-firebase/app(and auth) config plugins as in the Expo install docs
JS handling is unchanged: React Native Linking.getInitialURL() + Linking.addEventListener('url'). For more info on using
Expo with React Native Firebase, see our Expo docs.
JavaScript / React Native flow
Ensure @react-native-firebase/app and @react-native-firebase/auth are installed (see Authentication usage).
1. Send the link
Persist the email locally (for example AsyncStorage) before or immediately after sending — completing sign-in requires
the same address, and you must not put it in the continue URL query string.
import AsyncStorage from '@react-native-async-storage/async-storage';
import { getAuth, sendSignInLinkToEmail } from '@react-native-firebase/auth';
const CONTINUE_URL = 'https://YOUR_PROJECT_ID.firebaseapp.com'; // Authorized domain
const EMAIL_KEY = 'emailForSignIn';
async function sendSignInLink(email) {
await sendSignInLinkToEmail(getAuth(), email, {
url: CONTINUE_URL,
handleCodeInApp: true,
// Omit linkDomain unless you configured a custom Hosting link domain.
iOS: {
bundleId: 'com.yourcompany.yourapp',
},
android: {
packageName: 'com.yourcompany.yourapp',
installApp: true,
minimumVersion: '1',
},
});
await AsyncStorage.setItem(EMAIL_KEY, email);
}Modular sendSignInLinkToEmail requires actionCodeSettings (unlike the legacy namespaced helper defaults). See
Migrating to v25 / v26 for API notes.
2. Listen for the incoming URL
Use React Native Linking for both cold start (getInitialURL) and warm start (url events):
import { useEffect } from 'react';
import { Linking } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from '@react-native-firebase/auth';
const EMAIL_KEY = 'emailForSignIn';
async function completeFromUrl(url) {
if (!url || !isSignInWithEmailLink(getAuth(), url)) {
return;
}
const email = await AsyncStorage.getItem(EMAIL_KEY);
if (!email) {
// Same device: shouldn't happen. Other device / cleared storage:
// prompt the user to type the address the link was sent to, then continue.
return;
}
try {
await signInWithEmailLink(getAuth(), email, url);
await AsyncStorage.removeItem(EMAIL_KEY);
} catch (error) {
// Expired or reused links commonly surface as auth/invalid-action-code.
console.error(error.code, error.message);
}
}
useEffect(() => {
Linking.getInitialURL().then(completeFromUrl);
const sub = Linking.addEventListener('url', ({ url }) => {
completeFromUrl(url);
});
return () => sub.remove();
}, []);From React Native Firebase v26, isSignInWithEmailLink returns a synchronous boolean (matching firebase-js-sdk). Do
not await it. On v25 it returned Promise — see Migrating to v26.
After a successful signInWithEmailLink, any onAuthStateChanged listeners
receive the signed-in user.
3. Different device / missing stored email
If the user opens the link on another device, ask them to type the email again, then call signInWithEmailLink with that
address and the incoming URL. Firebase requires the email to match the address the link was sent to.
4. Link / re-authenticate with an email link
To link an email-link credential to an existing signed-in user, or to re-authenticate, build a credential from the
same incoming URL and call linkWithCredential / reauthenticateWithCredential:
import {
EmailAuthProvider,
getAuth,
linkWithCredential,
reauthenticateWithCredential,
} from '@react-native-firebase/auth';
const user = getAuth().currentUser;
if (user) {
const credential = EmailAuthProvider.credentialWithLink(email, url);
await linkWithCredential(user, credential);
// or: await reauthenticateWithCredential(user, credential);
}URL handling (App Links / Universal Links + isSignInWithEmailLink) is the same as for sign-in.
5. Email enumeration protection
Projects created after 2023-09-15 enable email enumeration protection
by default. Do not rely on fetchSignInMethodsForEmail for identifier-first UI when that protection is on — see the note
on Firebase's Android and
iOS email-link pages.
Checklist
- Email/Password + Email link providers enabled.
- Continue URL domain is Authorized.
- Default path: Android SHA fingerprints registered so Firebase can serve association files — or, for a custom domain,
association files live at/.well-known/and return JSON inline. - Android intent-filter uses
autoVerifyand your Hosting link host(s) (including/__/auth/links). - iOS Associated Domains match the host(s);
RCTLinkingManagerreceives Universal Links. - App stores the email, sends the link with
handleCodeInApp: true, then completes withsignInWithEmailLink. - Test on a physical device (App Links / Universal Links verification is unreliable or limited on many emulators/simulators).
Troubleshooting
| Symptom | What to check |
|---|---|
DYNAMIC_LINK_NOT_ACTIVATED / email still uses *.page.link |
Run Admin SDK mobileLinksConfig.domain: 'HOSTING_DOMAIN'. Do not set dynamicLinkDomain. |
| Link opens the browser, not the app | Physical device; AASA/assetlinks 200 + application/json; intent-filter / applinks: host is the Hosting link domain (PROJECT_ID.firebaseapp.com/__/auth/links), not only the continue URL. |
| iOS: Firebase email URL doesn't open the app, but pasting the Hosting URL does | Custom SMTP (e.g. SendGrid) wrapping the Auth URL in a redirect. Universal Links do not follow that redirect into the app. Use Firebase's default email sender, or a custom SMTP that does not wrap the destination URL. Reported in #8405. |
auth/invalid-action-code |
Link expired or already used; send a new one. |
auth/internal-error |
Check native logs (adb logcat / Console.app on a real device), not just the JS error. |
Related
Optional community helpers
The default Hosting path above is the simplest integration for most apps. The projects below were
built by community contributors for setups that need more than that — a custom domain, your brand in the sign-in
email (instead of the default firebaseapp.com link), a branded continue page, or association files on a host you already
operate. That work may genuinely help when you have those requirements.
React Native Firebase does not maintain, control, or endorse these tools; we cannot vouch for their security or long-term
availability. Prefer the default Hosting path when it fits, and evaluate each project for your own requirements.
No existing website — ready-made hosting helper
email-link-host is an optional community helper that provides a ready-made
hosting solution so you do not have to create association files and a continue-page host from scratch. It generatesassetlinks.json and apple-app-site-association from environment variables, serves a branded continue page, and can
deploy to Firebase Hosting, Cloudflare Pages, Vercel, Netlify, Amplify, or Docker.
Set your Android package name, SHA-256 fingerprints, and Apple Team ID / bundle ID, then confirm/.well-known/assetlinks.json and /.well-known/apple-app-site-association render as inline JSON (not a file download).
Existing website — form-based file generator
If you already operate a website or Hosting domain, App Universal Links Helper
(or run locally) is an optional community helper: fill in your hosts,
package name, fingerprints, and path rules (include /__/auth/links for Auth links) in a form, then download the generatedassetlinks.json, apple-app-site-association, AndroidManifest `` snippet, and optional adb / curl /swcutil verification commands. It does not upload files — publish the JSON under /.well-known/ on your domain.
End-to-end sample app
firebase-email-link-host-demo is an optional community sample that
wires React Native modular Auth + App Links + Universal Links + AsyncStorage. Useful starting points:src/services/firebaseAuth.ts, useEmailLinkAuth.ts, and the platform manifest / entitlements files.
Auth Multi Factor Auth (`docs/auth/multi-factor-auth.mdx`)
title: Multi-factor Auth next: /firestore/usage previous: /auth/oidc-auth
Before a user can enroll a second factor they need to verify their email. See
sendEmailVerification.
TOTP MFA
The official guide for Firebase web TOTP authentication explains the TOTP process well, including project prerequisites to enable the feature, as well as code examples.
The API details and usage examples may be combined with the full Phone auth example below to give you an MFA solution that fully supports TOTP or SMS MFA.
You may also find it useful to investigate the local / manual test screens that we use to verify this functionality.
Phone MFA
iOS Setup
Make sure to follow the official Identity Platform
documentation
to enable multi-factor authentication for your project and verify your app.
Enroll a new factor
Begin by obtaining a MultiFactorUser
instance for the current user. This is the entry point for most multi-factor
operations:
import {
PhoneAuthProvider,
PhoneMultiFactorGenerator,
getAuth,
multiFactor,
} from '@react-native-firebase/auth';
const multiFactorUser = await multiFactor(getAuth().currentUser);Request the session identifier and use the phone number obtained from the user
to send a verification code:
const session = await multiFactorUser.getSession();
const phoneOptions = {
phoneNumber,
session,
};
// Sends a text message to the user
const verificationId = await new PhoneAuthProvider(getAuth()).verifyPhoneNumber(phoneOptions);Once the user has provided the verification code received by text message, you
can complete the process:
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
await multiFactorUser.enroll(multiFactorAssertion, 'Optional display name for the user');You can inspect User#multiFactor for
information about the user's enrolled factors.
Sign-in flow using phone multi-factor
Ensure the account has already enrolled a second factor. Begin by calling the
default sign-in methods, for example email and password. If the account requires
a second factor to complete login, an exception will be raised:
import {
PhoneAuthProvider,
PhoneMultiFactorGenerator,
getAuth,
signInWithEmailAndPassword,
getMultiFactorResolver,
} from '@react-native-firebase/auth';
signInWithEmailAndPassword(getAuth(), email, password)
.then(() => {
// User has not enrolled a second factor
})
.catch(error => {
const { code } = error;
// Make sure to check if multi factor authentication is required
if (code === 'auth/multi-factor-auth-required') {
return;
}
// Other error
});Using the error object you can obtain aMultiFactorResolver instance and
continue the flow:
const resolver = getMultiFactorResolver(getAuth(), error);The resolver object has all the required information to prompt the user for a
specific factor:
if (resolver.hints.length > 1) {
// Use resolver.hints to display a list of second factors to the user
}
if (resolver.hints[0].factorId === PhoneMultiFactorGenerator.FACTOR_ID) {
// Continue with the sign-in flow
}Using a multi-factor hint and the session information you can send a
verification code to the user:
const hint = resolver.hints[0];
const verificationId = await new PhoneAuthProvider(getAuth()).verifyPhoneNumber({
multiFactorHint: hint,
session: resolver.session,
}); // Triggers message to userOnce the user has entered the verification code you can create a multi-factor
assertion and finish the flow:
const credential = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(credential);
resolver.resolveSignIn(multiFactorAssertion).then(userCredential => {
// additionally onAuthStateChanged will be triggered as well
});Upon successful sign-in, anyonAuthStateChanged listeners
will trigger with the new authentication state of the user.
To put the example together:
import {
PhoneAuthProvider,
PhoneMultiFactorGenerator,
getAuth,
signInWithEmailAndPassword,
getMultiFactorResolver,
} from '@react-native-firebase/auth';
signInWithEmailAndPassword(getAuth(), email, password)
.then(() => {
// User has not enrolled a second factor
})
.catch(error => {
const { code } = error;
// Make sure to check if multi factor authentication is required
if (code === 'auth/multi-factor-auth-required') {
const resolver = getMultiFactorResolver(getAuth(), error);
if (resolver.hints.length > 1) {
// Use resolver.hints to display a list of second factors to the user
}
if (resolver.hints[0].factorId === PhoneMultiFactorGenerator.FACTOR_ID) {
const hint = resolver.hints[0];
new PhoneAuthProvider(getAuth())
.verifyPhoneNumber({ multiFactorHint: hint, session: resolver.session }) // triggers the message to the user
.then(verificationId => setVerificationId(verificationId));
// Request verificationCode from user
const credential = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(credential);
resolver.resolveSignIn(multiFactorAssertion).then(userCredential => {
// additionally onAuthStateChanged will be triggered as well
});
}
}
});Testing
You can define test phone numbers and corresponding verification codes. The
official guide
contains more information on setting this up.
Auth Oidc Auth (`docs/auth/oidc-auth.mdx`)
title: OpenID Connect Authentication next: /auth/multi-factor-auth previous: /auth/email-link-auth
React Native Firebase provides supports integrating with OpenID Connect providers. The authentication with these
different providers is left to you to implement due to the various implementations and flows possible.
Here we will demonstrate a minimal example of how you could do this using the package react-native-app-auth to authenticate with the provider. Then after we have authenticated with the provider, we use the ID Token from the provider to authenticate with react-native-firebase. But you have to handle the flow to get the ID token and you should do things like logging the user out from the provider when they logout or revoke the token. Again this all depends on the provider, your flow and your use-case.
Getting started
To get started with OpenID Connect authentication you need to do the following:
- Setup or get the configuration from the provider you want to use
- Add the provider in the firebase console
- Authenticate in the app using
react-native-app-authandreact-native-firebase
1. Setup or get the configuration from the provider you want to use
As stated before, this will vary a lot from provider to provider and your use-case. You need to find and look the documentation for the provider you want to use and follow that documentation to setup a working provider.
You can see examples of "Tested OpenID providers" from react-native-app-auth here and how you do this will depend on what provider you want to use. But you need to complete the setup or configuration of the provider you want to use before you continue here.
2. Add the provider in the Firebase console
Doing the steps below will allow you to add the provider to the Firebase project.
If the provider is not added there, you won't be able to use the signInWithCredential method, since Firebase will not be able to use the credential if the provider does not exist in the project.
- Firebase console in the project you want to add OpenID Connect to
- Authentication
- Sign-in method
- If you have added "Sign-in providers" already, click "Add new provider"
- Under "Custom providers" choose "OpenID Connect"
- Toggle on the Enabled at the top to the right of "Open ID Connect"
- Fill out the details like: "Name", "Client ID", "Issuer (URL)" and "Client secret". These values have to correspond to the OpenID Connect provider you want to use.
- Note down the Provider ID below name, if you type in "azure_test" in the name field. Notice how it says below the field: "Provider ID: oidc.azure_test" so this value will be prepended with "oidc." We will use this later when authenticating the user.
3. Authenticate in the app using "react-native-app-auth" and "react-native-firebase"
Before you use react-native-app-auth you have to complete the setup in their docs.
The example below demonstrates how you could setup such a flow within your own application:
import { OIDCAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth';
import { authorize } from 'react-native-app-auth';
// using react-native-app-auth to get oauth token from Azure AD
const config = {
issuer: 'https://login.microsoftonline.com/XXX/v2.0',
clientId: 'XXXX',
redirectUrl: 'msauth.your.bundle.id://auth/',
scopes: ['openid', 'profile', 'email', 'offline_access'],
useNonce: false,
};
// Log in to get an authentication token
const authState = await authorize(config);
const credential = OIDCAuthProvider.credential(
'azure_test', // this is the "Provider ID" value from the firebase console
authState.idToken,
);
await signInWithCredential(getAuth(), credential);Auth Phone Auth (`docs/auth/phone-auth.mdx`)
title: Phone Authentication next: /auth/email-link-auth previous: /auth/social-auth
Phone authentication allows users to sign in to Firebase using their phone as the authenticator. An SMS message is sent
to the user via their phone number containing a unique code. Once the code has been authorized, the user is able to sign
in to Firebase.
Phone numbers that end users provide for authentication will be sent and stored by Google to improve our spam and abuse
prevention across Google services, including but not limited to Firebase. Developers should ensure they have appropriate
end-user consent prior to using the Firebase Authentication phone number sign-in service.
Firebase Phone Auth is not supported in all countries. Please see their FAQs for more information.
Ensure the "Phone" sign-in provider is enabled on the Firebase Console.
iOS Setup
Ensure that all parts of step 1 and 2 from the official firebase iOS phone auth docs have been followed, noting in particular that you may need to re-download your firebase GoogleService-Info.plist file and for the reCAPTCHA flow to work you must make sure you have added your custom URL scheme to your project plist file.
Phone auth requires app verification, and the automatic app verification process uses data-only firebase cloud messages to the app. Data-only cloud messaging only works on real devices where the app has background refresh enabled. If background refresh disabled, or if using the Simulator, app verification uses the fallback reCAPTCHA flow allowing you to check if it is configured correctly.
For reliable automated testing, you may want to disable both automatic and fallback reCAPTCHA app verification for your app. To do this, you may disable app verification in AuthSettings prior to calling any phone auth methods.
Android Setup
Ensure that all parts of step 1 and 2 from the official firebase Android phone auth docs have been followed.
To bypass Play Integrity for manual testing, you may force reCAPTCHA to be used prior to calling verifyPhoneNumber.
Expo Setup
To use phone auth in an expo app, add the @react-native-firebase/auth config plug-in to the plugins section of your app.json. This is in addition to the @react-native-firebase/app plugin.
{
"expo": {
"plugins": ["@react-native-firebase/app", "@react-native-firebase/auth"]
}
}The @react-native-firebase/auth config plugin is not required for all auth providers, but it is required to use phone auth. The plugin will set up reCAPTCHA verification for you on iOS.
On Expo SDK 58+ (UIScene life cycle), the plugin patches SceneDelegate so Firebase Auth can handle reCAPTCHA redirect URLs with Auth.auth().canHandle(_:) before they reach Expo Router. That matches Firebase’s documented scene(_:openURLContexts:) path for an in-app reCAPTCHA return; Auth does not require a cold-start willConnectTo handler for this flow.
The recommendation is to use a custom development client. For more info on using Expo with React Native Firebase, see our Expo docs.
Sign-in
The module provides a signInWithPhoneNumber method which accepts a phone number. Firebase sends an SMS message to the
user with a code, which they must then confirm. The signInWithPhoneNumber method returns a confirmation method which accepts
a code. Based on whether the code is correct for the device, the method rejects or resolves.
The example below demonstrates how you could setup such a flow within your own application:
/* Detailed source-code truncated for AI context efficiency. */Upon successful sign-in, any onAuthStateChanged listeners will trigger
with the new authentication state of the user.
Testing
Firebase provides support for locally testing phone numbers. For local testing to work, you must have ensured your local
machine SHA1 debug key was added whilst creating your application on the Firebase Console. View the Getting Started
guide on how to set this up.
On the Firebase Console, select the "Phone" authentication provider and click on the
"Phone numbers for testing" dropdown.
Enter a new phone number (e.g. +44 7444 555666) and a test code (e.g. 123456).
Once added, the number can be used with the signInWithPhoneNumber method, and entering the code specified will
cause a successful sign-in.
MFA-like Account Creation
After successfully creating a user with an email and password (see Authentication/Usage/Email/Password sign-in), use the verifyPhoneNumber method to send a verification code to a user's phone number and if the user enters the correct code, link the phone number to the authenticated user's account. This creates a MFA-like authentication flow for account creation. However, to implement MFA with firebase, your app must call additional methods and use Google Cloud Identity Platform, which is a paid service, details available in this guide https://cloud.google.com/identity-platform/docs/web/mfa
/* Detailed source-code truncated for AI context efficiency. */Auth Social Auth (`docs/auth/social-auth.mdx`)
title: Social Authentication next: /auth/phone-auth previous: /auth/usage
React Native Firebase provides support for integrating with different social platforms. The authentication with these
different platforms is left to the developer to implement due to the various implementations and flows possible using
their OAuth APIs.
Social providers
Apple
Starting April 2020, all existing applications using external 3rd party login services (such as Facebook, Twitter, Google etc)
must ensure that Apple Sign-In is also provided. To learn more about these new guidelines, view the Apple announcement.
Apple Sign-In is not required for Android devices.
To integrate Apple Sign-In on your iOS applications, you need to install a 3rd party library to authenticate with Apple.
Once authentication is successful, a Firebase credential can be used to sign the user into Firebase with their Apple account.
To get started, you must first install the react-native-apple-authentication
library. There are a number of prerequisites to using the library, including
setting up your Apple Developer account to enable Apple Sign-In.
Ensure the "Apple" sign-in provider is enabled on the Firebase Console.
Once setup, we can trigger an initial request to allow the user to sign in with their Apple account, using a pre-rendered
button the react-native-apple-authentication library provides:
import React from 'react';
import { AppleButton } from '@invertase/react-native-apple-authentication';
function AppleSignIn() {
return (
<AppleButton
buttonStyle={AppleButton.Style.WHITE}
buttonType={AppleButton.Type.SIGN_IN}
style={{
width: 160,
height: 45,
}}
onPress={() => onAppleButtonPress().then(() => console.log('Apple sign-in complete!'))}
/>
);
}When the user presses the pre-rendered button, we can trigger the initial sign-in request using the performRequest method,
passing in the scope required for our application:
import { AppleAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth';
import { appleAuth } from '@invertase/react-native-apple-authentication';
async function onAppleButtonPress() {
// Start the sign-in request
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
// As per the FAQ of react-native-apple-authentication, the name should come first in the following array.
// See: https://github.com/invertase/react-native-apple-authentication#faqs
requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
});
// Ensure Apple returned a user identityToken
if (!appleAuthRequestResponse.identityToken) {
throw new Error('Apple Sign-In failed - no identify token returned');
}
// Create a Firebase credential from the response
const { identityToken, nonce } = appleAuthRequestResponse;
const appleCredential = AppleAuthProvider.credential(identityToken, nonce);
// Sign the user in with the credential
return signInWithCredential(getAuth(), appleCredential);
}Upon successful sign-in, any onAuthStateChanged listeners will trigger
with the new authentication state of the user.
Apple also requires that the app revoke the Sign in with Apple token when the user chooses to delete their account. This can be accomplished with the revokeToken API.
import { getAuth, revokeToken } from '@react-native-firebase/auth';
import { appleAuth } from '@invertase/react-native-apple-authentication';
async function revokeSignInWithAppleToken() {
// Get an authorizationCode from Apple
const { authorizationCode } = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.REFRESH,
});
// Ensure Apple returned an authorizationCode
if (!authorizationCode) {
throw new Error('Apple Revocation failed - no authorizationCode returned');
}
// Revoke the token
return revokeToken(getAuth(), authorizationCode);
}There is a community-supported React Native library which wraps around
the native Facebook SDKs to enable Facebook sign-in.
Before getting started, ensure you have installed the library, configured your Android & iOS applications and
setup your Facebook Developer Account
to enable Facebook Login.
Ensure the "Facebook" sign-in provider is enabled on the Firebase Console.
Once setup, we can trigger the login flow with Facebook by calling the logInWithPermissions method on the LoginManager
class:
import React from 'react';
import { Button } from 'react-native';
function FacebookSignIn() {
return (
<Button
title="Facebook Sign-In"
onPress={() => onFacebookButtonPress().then(() => console.log('Signed in with Facebook!'))}
/>
);
}The onFacebookButtonPress can then be implemented as follows:
import { FacebookAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth';
import { LoginManager, AccessToken } from 'react-native-fbsdk-next';
async function onFacebookButtonPress() {
// Attempt login with permissions
const result = await LoginManager.logInWithPermissions(['public_profile', 'email']);
if (result.isCancelled) {
throw 'User cancelled the login process';
}
// Once signed in, get the users AccessToken
const data = await AccessToken.getCurrentAccessToken();
if (!data) {
throw 'Something went wrong obtaining access token';
}
// Create a Firebase credential with the AccessToken
const facebookCredential = FacebookAuthProvider.credential(data.accessToken);
// Sign-in the user with the credential
return signInWithCredential(getAuth(), facebookCredential);
}Facebook Limited Login (iOS only)
To use Facebook Limited Login instead of "classic" Facebook Login, the onFacebookButtonPress can then be implemented as follows:
import { FacebookAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth';
import { LoginManager, AuthenticationToken } from 'react-native-fbsdk-next';
import { sha256 } from 'react-native-sha256';
async function onFacebookButtonPress() {
// Create a nonce and the corresponding
// sha256 hash of the nonce
const nonce = '123456';
const nonceSha256 = await sha256(nonce);
// Attempt login with permissions and limited login
const result = await LoginManager.logInWithPermissions(
['public_profile', 'email'],
'limited',
nonceSha256,
);
if (result.isCancelled) {
throw 'User cancelled the login process';
}
// Once signed in, get the users AuthenticationToken
const data = await AuthenticationToken.getAuthenticationTokenIOS();
if (!data) {
throw 'Something went wrong obtaining authentication token';
}
// Create a Firebase credential with the AuthenticationToken
// and the nonce (Firebase will validates the hash against the nonce)
const facebookCredential = FacebookAuthProvider.credential(data.authenticationToken, nonce);
// Sign-in the user with the credential
return signInWithCredential(getAuth(), facebookCredential);
}Upon successful sign-in, any onAuthStateChanged listeners will trigger
with the new authentication state of the user.
Firebase does not ship a Google sign-in UI. You install a community library to obtain a Google ID token, then pass it to GoogleAuthProvider.credential() and signInWithCredential().
Ensure the "Google" sign-in provider is enabled on the Firebase Console.
On Android, Google recommends Credential Manager for Sign in with Google. Two maintained React Native libraries can provide that flow:
| Library | Credential Manager (Android) | Cost | Notes |
|---|---|---|---|
react-native-nitro-google-signin |
Yes | Free (MIT) | Universal / One Tap-style API via Nitro Modules; requires react-native-nitro-modules |
@react-native-google-signin/google-signin |
Yes with Universal Sign-In; no on the free public GoogleSignin API |
Paid for Credential Manager; free for legacy Android SDK | Universal Sign-In uses GoogleOneTapSignIn; the free public build is documented in the section below |
The sections below show Firebase integration for each approach. For native setup (OAuth clients, SHA-1, Expo config plugins), follow that library's documentation.
react-native-nitro-google-signin
react-native-nitro-google-signin is a free, MIT-licensed option that uses Credential Manager on Android and the Google Sign-In SDK on iOS. It is a good fit when you want modern Android sign-in without a paid Universal Sign-In license from @react-native-google-signin/google-signin.
Install the package and its peer dependency:
yarn add react-native-nitro-google-signin react-native-nitro-modulesThen follow the installation and [Google Cloud setup](https://react-native-nitro-google-sign-in.github.io/docs/setup