rembrembdocs

Migrate from Firebase Firestore to Supabase

Migrate your Firebase Firestore database to a Supabase Postgres database.


Supabase provides several tools to convert data from a Firebase Firestore database to a Supabase Postgres database. The process copies the entire contents of a single Firestore collection to a single Postgres table.

The Firestore collection is "flattened" and converted to a table with basic columns of one of the following types: text, numeric, boolean, or jsonb. If your structure is more complex, you can write a program to split the newly-created json file into multiple, related tables before you import your json file(s) to Supabase.

Set up the migration tool #

  1. Clone the firebase-to-supabase repository:

    1git clone https://github.com/supabase-community/firebase-to-supabase.git
    
  2. In the /firestore directory, create a file named supabase-service.json with the following contents:

    1{2  "host": "database.server.com",3  "password": "secretpassword",4  "user": "postgres",5  "database": "postgres",6  "port": 54327}
    
  3. On your project dashboard, click Connect

  4. Under the Session pooler, click on the View parameters under the connect string. Replace the Host and User fields with the values shown.

  5. Enter the password you used when you created your Supabase project in the password entry in the supabase-service.json file.

Generate a Firebase private key #

  1. Log in to your Firebase Console and open your project.
  2. Click the gear icon next to Project Overview in the sidebar and select Project Settings.
  3. Click Service Accounts and select Firebase Admin SDK.
  4. Click Generate new private key.
  5. Rename the downloaded file to firebase-service.json.

Command line options#

List all Firestore collections#

node collections.js

Dump Firestore collection to JSON file#

node firestore2json.js <collectionName> [<batchSize>] [<limit>]

Customize the JSON file with hooks#

You can customize the way your JSON file is written using a custom hook. A common use for this is to "flatten" the JSON file, or to split nested data into separate, related database tables. For example, you could take a Firestore document that looks like this:

1[{ "user": "mark", "score": 100, "items": ["hammer", "nail", "glue"] }]

And split it into two files (one table for users and one table for items):

1[{ "user": "mark", "score": 100 }]
1[2  { "user": "mark", "item": "hammer" },3  { "user": "mark", "item": "nail" },4  { "user": "mark", "item": "glue" }5]

Import JSON file to Supabase (Postgres) #

node json2supabase.js <path_to_json_file> [<primary_key_strategy>] [<primary_key_name>]

Custom hooks#

Hooks are used to customize the process of exporting a collection of Firestore documents to JSON. They can be used for:

Write a custom hook#

Create a .js file for your collection#

If your Firestore collection is called users, create a file called users.js in the current folder.

Construct your .js file#

The basic format of a hook file looks like this:

1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2  // modify the doc here3  return doc4}
Parameters

Examples#

Add a new (unique) numeric key to a collection#

1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2  doc.unique_key = recordCounter[collectionName] + 13  return doc4}

Add a timestamp of when this record was dumped from Firestore#

1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2  doc.dump_time = new Date().toISOString()3  return doc4}

Flatten JSON into separate files#

Flatten the users collection into separate files:

1[2  {3    "uid": "abc123",4    "name": "mark",5    "score": 100,6    "weapons": ["toothpick", "needle", "rock"]7  },8  {9    "uid": "xyz789",10    "name": "chuck",11    "score": 9999999,12    "weapons": ["hand", "foot", "head"]13  }14]

The users.js hook file:

1module.exports = (collectionName, doc, recordCounters, writeRecord) => {2  for (let i = 0; i < doc.weapons.length; i++) {3    const weapon = {4      uid: doc.uid,5      weapon: doc.weapons[i],6    }7    writeRecord('weapons', weapon, recordCounters)8  }9  delete doc.weapons // moved to separate file10  return doc11}

The result is two separate JSON files:

1[2  { "uid": "abc123", "name": "mark", "score": 100 },3  { "uid": "xyz789", "name": "chuck", "score": 9999999 }4]
1[2  { "uid": "abc123", "weapon": "toothpick" },3  { "uid": "abc123", "weapon": "needle" },4  { "uid": "abc123", "weapon": "rock" },5  { "uid": "xyz789", "weapon": "hand" },6  { "uid": "xyz789", "weapon": "foot" },7  { "uid": "xyz789", "weapon": "head" }8]

Resources#

Migrate to Supabase#

Contact us if you need more help migrating your project.