Skip to main content

How to Migrate from Firebase to Supabase

·OSSAlt Team
firebasesupabasemigrationbackendguide

How to Migrate from Firebase to Supabase

Firebase locks you into Google's ecosystem with proprietary NoSQL (Firestore) and opaque pricing. Supabase gives you PostgreSQL, open source, and predictable costs. The migration is significant but well-documented. Here's how.

What Changes

FirebaseSupabaseMigration Effort
Firestore (NoSQL)PostgreSQL (relational)🔴 High — schema redesign
Firebase AuthSupabase Auth🟡 Medium — user migration
Cloud StorageSupabase Storage🟢 Low — file migration
Realtime DatabaseSupabase Realtime🟡 Medium — API changes
Cloud FunctionsSupabase Edge Functions🟡 Medium — rewrite
Firebase HostingNot includedUse Vercel/Netlify
FCM (Push)Not includedUse OneSignal/ntfy

Step 1: Set Up Supabase

Cloud:

  1. Sign up at supabase.com
  2. Create a new project
  3. Note your project URL and anon key

Self-hosted:

git clone https://github.com/supabase/supabase.git
cd supabase/docker
cp .env.example .env
docker compose up -d

Step 2: Migrate Database (Firestore → PostgreSQL)

This is the biggest change. Firestore is document-based (NoSQL); PostgreSQL is relational.

Export Firestore data:

// Node.js script to export Firestore collections
const admin = require('firebase-admin');
const fs = require('fs');

admin.initializeApp();
const db = admin.firestore();

async function exportCollection(name) {
  const snapshot = await db.collection(name).get();
  const data = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
  fs.writeFileSync(`${name}.json`, JSON.stringify(data, null, 2));
}

await exportCollection('users');
await exportCollection('posts');
await exportCollection('comments');

Design PostgreSQL schema:

-- Convert Firestore documents to relational tables
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  avatar_url TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE posts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id),
  title TEXT NOT NULL,
  content TEXT,
  tags TEXT[],
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE comments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  post_id UUID REFERENCES posts(id),
  user_id UUID REFERENCES users(id),
  body TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Import data:

// Import exported JSON into Supabase
const { createClient } = require('@supabase/supabase-js');
const users = require('./users.json');

const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY);

for (const user of users) {
  await supabase.from('users').insert({
    email: user.email,
    name: user.name,
    avatar_url: user.avatarUrl,
    created_at: user.createdAt?.toDate?.() || new Date(),
  });
}

Step 3: Migrate Authentication

Export Firebase users:

# Use Firebase CLI
firebase auth:export users.json --format=json

Import to Supabase: Supabase has a migration tool for Firebase Auth users. Use the Admin API:

const { createClient } = require('@supabase/supabase-js');
const users = require('./users.json');

const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY);

for (const user of users.users) {
  await supabase.auth.admin.createUser({
    email: user.email,
    email_confirm: true,
    user_metadata: { name: user.displayName },
  });
}

Users will need to reset passwords (or use magic link/OAuth).

Step 4: Migrate Storage

// Download from Firebase Storage, upload to Supabase Storage
const { getStorage } = require('firebase-admin/storage');
const bucket = getStorage().bucket();

// List and download files
const [files] = await bucket.getFiles({ prefix: 'uploads/' });
for (const file of files) {
  const [content] = await file.download();
  await supabase.storage
    .from('uploads')
    .upload(file.name, content);
}

Step 5: Update Client Code

Before (Firebase):

import { collection, getDocs } from 'firebase/firestore';
const snapshot = await getDocs(collection(db, 'posts'));
const posts = snapshot.docs.map(doc => doc.data());

After (Supabase):

import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
const { data: posts } = await supabase.from('posts').select('*');

Step 6: Set Up Row Level Security

-- Enable RLS on tables
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Users can read all posts
CREATE POLICY "Public read" ON posts FOR SELECT USING (true);

-- Users can only edit their own posts
CREATE POLICY "Own posts" ON posts FOR ALL
  USING (auth.uid() = user_id);

The Bottom Line

Firebase to Supabase is a significant migration — especially the Firestore to PostgreSQL conversion. But you gain: SQL power, open source, predictable pricing, and no vendor lock-in. Plan for 2-4 weeks of migration work for a medium-sized app.


Compare BaaS platforms on OSSAlt — database options, auth features, and pricing side by side.