---
title: Cloud Firestore
description: Installation and getting started with 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.

```bash
# 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 install
```

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](/firestore/usage/installation/ios) and [Android](/firestore/usage/installation/android).

If you have started to receive a `app:mergeDexDebug` error after adding Cloud Firestore, please read the
[Enabling Multidex](/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](/migrating-to-v26#new-architecture-requirement). |

**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.

<YouTube id="QcsAb2RR52c" />

# 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:

```js
import { collection, getFirestore } from '@react-native-firebase/firestore';

const db = getFirestore();
const usersCollection = collection(db, 'Users');
```

The `collection` function returns a [`CollectionReference`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/CollectionReference.html) 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:

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentReference.html).

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](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/Timestamp.html),
[GeoPoints](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/GeoPoint.html), [Bytes](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/Bytes.html#frombase64string) 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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/CollectionReference.html)
or `getDoc` on a [`DocumentReference`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentReference.html):

```js
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):

```js
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 any
`useEffect` hooks to automatically unsubscribe when the hook needs to unsubscribe itself:

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/QuerySnapshot.html) (for
collection queries) or a [`DocumentSnapshot`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentSnapshot.html) (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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/QuerySnapshot.html) 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:

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/QueryDocumentSnapshot.html), which
allows you to access specific information about a document (see below).

#### `DocumentSnapshot`

A [`DocumentSnapshot`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentSnapshot.html) is returned from a query to a specific document, or as part
of the documents returned via a [`QuerySnapshot`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/QuerySnapshot.html). 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:

```js
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:

```js
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:

```js
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:

```js
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](https://firebase.google.com/docs/firestore/query-data/queries).

You can combine multiple filters using `and()` and `or()` composite constraints.
For example:

```js
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', '==', 'tim@example.com'),
  ),
);
```

You can use the `and()` function to make logical AND queries:

```js
const snapshot = await getDocs(
  query(
    collection(db, 'Users'),
    and(where('user', '==', 'Tim'), where('email', '==', 'tim@example.com')),
  ),
);
```

You can use the `or()` function to make logical OR queries:

```js
const snapshot = await getDocs(
  query(
    collection(db, 'Users'),
    or(
      and(where('user', '==', 'Tim'), where('email', '==', 'tim@example.com')),
      and(where('user', '==', 'Dave'), where('email', '==', 'dave@example.com')),
    ),
  ),
);
```

For an understanding of what queries are possible, please consult the query limitation documentation on the official
[Firebase Firestore documentation](https://firebase.google.com/docs/firestore/query-data/queries#limits_on_or_queries).

#### Limiting

To limit the number of documents returned from a query, use the `limit` constraint:

```js
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:

```js
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:

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentSnapshot.html) instead of a specific value. For example:

```js
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](https://firebase.google.com/docs/firestore/manage-data/structure-data) 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](https://firebase.google.com/docs/firestore/manage-data/add-data)

## Adding documents

To add a new document to a collection, use `addDoc` with a [`CollectionReference`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/CollectionReference.html):

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentReference.html) instead:

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/types/firestore/DocumentReference.html).
if you'd like to update a document instead, use `updateDoc`:

```js
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:

```js
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](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/Timestamp.html),
[GeoPoints](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/GeoPoint.html), [Bytes](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/Bytes.html#frombase64string) and array management.

To store [`GeoPoint`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/GeoPoint.html) values, provide the latitude and longitude to a new instance of the
class:

```js
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](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/Bytes.html#frombase64string) (for example of a `Base64` image string), provide the string to the static
`fromBase64String` method on the class:

```js
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:

```js
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):

```js
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):

```js
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`](https://invertase.github.io/react-native-firebase/_react-native-firebase/firestore/modular/deleteDoc.html):

```js
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`:

```js
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](/firestore/usage#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`:

```js
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:

```js
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](https://firebase.google.com/docs/firestore/security/get-started).

## 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:

```js
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`:

```js
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](https://firebase.google.com/docs/firestore/bundles) as well as their "[Bundle Solutions](https://firebase.google.com/docs/firestore/solutions/serve-bundles)" page
