Use Cloud Firestore with Firebase Realtime Database

You can use both Firebase Realtime Database and Cloud Firestore in your app, and leverage each database solution's benefits to fit your needs. For example, you might want to leverage Realtime Database's support for presence, as outlined in Build Presence in Cloud Firestore.

Learn more about the differences between the databases.

Moving data to Cloud Firestore

If you've decided you want to migrate some of your data from Realtime Database to Cloud Firestore, consider the following flow. Because every database has unique needs and structural considerations, there isn't an automated migration path. Instead, you can follow this general progression:

  1. Map the data structure and security rules from Realtime Database to Cloud Firestore. Both Realtime Database and Cloud Firestore rely on Firebase Authentication, so you don't need to change user authentication for your app. However, the security rules and data model are different and it's important to carefully account for those divergences before you start moving data to Cloud Firestore.

  2. Move historical data. As you're setting up your new data structure in Cloud Firestore, you can map and move existing data from Realtime Database to your new Cloud Firestore instance. However, if you're using both databases in your app, you don't need to move historical data out of Realtime Database.

  3. Mirror new data to Firestore in realtime. Use Cloud Functions to write new data to your new Cloud Firestore database as it gets added to Realtime Database.

  4. Make Cloud Firestore your primary database for the migrated data. Once you've migrated some of your data, use Cloud Firestore as your primary database and reduce your Realtime Database use for the migrated data. Consider versions of your app that are still tied to Realtime Database for that data and how you plan to continue supporting them.

Make sure you account for billing costs for both Realtime Database and Cloud Firestore.

Map your data

Data in Realtime Database is structured as a single tree, while Cloud Firestore supports more explicit data hierarchies through documents, collections, and subcollections. If you move some of your data from Realtime Database to Cloud Firestore, you might want to consider a different architecture for your data.

Major differences to consider

If you move data from your existing Realtime Database tree to Cloud Firestore documents and collections, keep in mind the following major differences between the databases that might impact how you structure data in Cloud Firestore:

  • Shallow queries offer more flexibility in hierarchical data structures.
  • Complex queries offer more granularity and reduce the need for duplicate data.
  • Query cursors offer more robust pagination.
  • Transactions no longer require a common root for all your data, and are more efficient.
  • Billing costs differ between Realtime Database and Cloud Firestore. In many cases, Cloud Firestore might be more expensive than Realtime Database, particularly if you rely on many small operations. Consider reducing the number of operations on your database and avoiding unnecessary writes. Learn more about the differences in billing between Realtime Database and Cloud Firestore.

Best practices in action

The following example reflects some of the considerations you might make as you shift your data between databases. You can leverage shallow reads and improved querying capabilities for more natural data structures than you may have used with Realtime Database.

Consider a city guide app that helps users find notable landmarks in cities around the world. Since Realtime Database lacks shallow reads, you might have had to structure the data in two top-level nodes, as follows:

// /cities/$CITY_KEY
{
  name: "New York",
  population: 8000000,
  capital: False
}

// /city-landmark/$CITY_KEY/$LANDMARK_KEY
{
  name: "Empire State Building",
  category: "Architecture"
}

Cloud Firestore has shallow reads, so querying for documents in a collection doesn't pull in data from subcollections. Consequently, you can store landmark information in a subcollection:

// /cities/$CITY_ID
{
  name: "New York",
  population: 8000000,
  capital: False,
  landmarks: [... subcollection ...]
}

Documents have a maximum size of 1MB, which is another reason to store landmarks as a subcollection, keeping each city document small, rather than bloating documents with nested lists.

Cloud Firestore's advanced querying capabilities reduce the need to duplicate data for common access patterns. For example, consider a screen in the city guide app that shows all of the capital cities ordered by population. In Realtime Database, the most efficient way to do this is to maintain a separate list of capital cities that duplicates data from the cities list, as follows:

{
   cities: {
    // ...
   },

   capital-cities: {
     // ...
   }
}

In Cloud Firestore, you can express a list of capital cities in order of population as a single query:

db.collection('cities')
    .where('capital', '==', true)
    .orderBy('population')

Read more about the Cloud Firestore data model and take a look at our Solutions for more ideas on how to structure your Cloud Firestore database.

Secure your data

Whether you're using Cloud Firestore Security Rules for Android, Apple, or Web clients, or Identity Access Management (IAM) for servers, make sure you're securing your data in Cloud Firestore as well as Realtime Database. User authentication is handled by Authentication for both databases, so you don't need to change your implementation of Authentication when you start using Cloud Firestore.

Major differences to consider

  • Mobile and web SDKs use Cloud Firestore Security Rules, while server SDKs use Identity Access Management (IAM) to secure data.
  • Cloud Firestore Security Rules don't cascade unless you use a wildcard. Documents and collections don't otherwise inherit rules.
  • You no longer need to validate data separately (as you did in Realtime Database).
  • Cloud Firestore checks rules before executing a query to make sure that the user has the appropriate access for all data returned by the query.

Move historical data to Cloud Firestore

Once you've mapped your data and security structures to Cloud Firestore's data and security models, you can start adding your data. If you plan to query historical data after you move your app from Realtime Database to Cloud Firestore, add an export of your old data to your new Cloud Firestore database. If you plan to use both Realtime Database and Cloud Firestore in your app, you can skip this step.

To avoid overwriting new data with old data, you might want to add your historical data first. If you add new data to both databases simultaneously, as discussed in the next step, make sure you give precedence to new data added to Cloud Firestore by Cloud Functions.

To migrate historical data to Cloud Firestore, follow these steps:

  1. Export your data from Realtime Database or use a recent backup.
    1. Go to the Realtime Database section in the Firebase console.
    2. From the Data tab, select your database's root-level node and select Export JSON from the menu.
  2. Create your new database in Cloud Firestore and add your data.

    Consider the following strategies as you move some of your data to Cloud Firestore:

    • Write a custom script that ports your data for you. While we can't offer a template for this script, because every database will have unique needs, Cloud Firestore experts on our Slack channel or on Stack Overflow can review your script or offer advice for your specific situation.
    • Use the server SDKs (Node.js, Java, Python, or Go) to write data directly to Cloud Firestore. For instructions on setting up the server SDKs, see Get Started.
    • To expedite large data migrations, use batched writes and send up to 500 operations in a single network request.
    • To stay under Cloud Firestore rate limits, limit operations to 500 writes/second for each collection.

Add new data to Cloud Firestore

To maintain parity between your databases, add new data to both databases in realtime. Use Cloud Functions to trigger a write to Cloud Firestore whenever a client writes to Realtime Database. Make sure that Cloud Firestore gives precedence to new data coming from Cloud Functions over any writes you're making from your historical data migration.

Create a function to write new or changing data to Cloud Firestore every time a client writes data to Realtime Database. Learn more about Realtime Database triggers for Cloud Functions.

Make Cloud Firestore your primary database for the migrated data

If you've decided to use Cloud Firestore as your primary database for some of your data, make sure you account for any data-mirroring functions you've set up and validate your Cloud Firestore Security Rules.

  1. If you used Cloud Functions to maintain parity between your databases, make sure you're not duplicating write operations across both databases in a loop. Switch your function to write to a single database, or remove the function completely and start phasing out write functionality for the migrated data in apps still tied to Realtime Database. How you handle this for your app depends on your specific needs and your users.

  2. Verify that your data is properly secured. Validate your Cloud Firestore Security Rules or IAM setup.