How to Migrate from Firebase to Supabase
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
| Firebase | Supabase | Migration Effort |
|---|---|---|
| Firestore (NoSQL) | PostgreSQL (relational) | 🔴 High — schema redesign |
| Firebase Auth | Supabase Auth | 🟡 Medium — user migration |
| Cloud Storage | Supabase Storage | 🟢 Low — file migration |
| Realtime Database | Supabase Realtime | 🟡 Medium — API changes |
| Cloud Functions | Supabase Edge Functions | 🟡 Medium — rewrite |
| Firebase Hosting | Not included | Use Vercel/Netlify |
| FCM (Push) | Not included | Use OneSignal/ntfy |
Step 1: Set Up Supabase
Cloud:
- Sign up at supabase.com
- Create a new project
- 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.