Supabase logoKB

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:

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

    {
      "host": "database.server.com",
      "password": "secretpassword",
      "user": "postgres",
      "database": "postgres",
      "port": 5432
    }
  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. Sign 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:

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

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

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

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:

module.exports = (collectionName, doc, recordCounters, writeRecord) => {
  // modify the doc here
  return doc
}
Parameters

Examples

Add a new (unique) numeric key to a collection

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

Add a timestamp of when this record was dumped from Firestore

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

Flatten JSON into separate files

Flatten the users collection into separate files:

[
  {
    "uid": "abc123",
    "name": "mark",
    "score": 100,
    "weapons": ["toothpick", "needle", "rock"]
  },
  {
    "uid": "xyz789",
    "name": "chuck",
    "score": 9999999,
    "weapons": ["hand", "foot", "head"]
  }
]

The users.js hook file:

module.exports = (collectionName, doc, recordCounters, writeRecord) => {
  for (let i = 0; i < doc.weapons.length; i++) {
    const weapon = {
      uid: doc.uid,
      weapon: doc.weapons[i],
    }
    writeRecord('weapons', weapon, recordCounters)
  }
  delete doc.weapons // moved to separate file
  return doc
}

The result is two separate JSON files:

[
  { "uid": "abc123", "name": "mark", "score": 100 },
  { "uid": "xyz789", "name": "chuck", "score": 9999999 }
]
[
  { "uid": "abc123", "weapon": "toothpick" },
  { "uid": "abc123", "weapon": "needle" },
  { "uid": "abc123", "weapon": "rock" },
  { "uid": "xyz789", "weapon": "hand" },
  { "uid": "xyz789", "weapon": "foot" },
  { "uid": "xyz789", "weapon": "head" }
]

Resources

Migrate to Supabase

Contact us if you need more help migrating your project.