📖Siyuan's Notes
中文
Tools2026-09-27

Supabase vs Firebase: Complete Comparison Guide for Developers in 2026

#Supabase#Firebase#BaaS#Backend#Database

Supabase vs Firebase: Complete Comparison Guide for Developers in 2026

Supabase and Firebase are the two dominant backend-as-a-service (BaaS) platforms. Firebase, launched by Google in 2014, pioneered the space with its real-time NoSQL database and serverless functions. Supabase, launched in 2020, is the open-source alternative built on PostgreSQL, offering real-time, auth, storage, and edge functions. Choosing between them impacts your data model, query flexibility, scaling costs, and vendor lock-in. This guide compares every aspect — database, authentication, real-time, storage, functions, pricing, migration, and ecosystem — with real numbers, code examples, and a decision framework so you can pick the right one for your project.

Quick Comparison Summary

Feature Supabase Firebase
Database PostgreSQL (relational) Firestore (NoSQL document)
Database type SQL NoSQL
Real-time Yes (Postgres changes) Yes (native)
Authentication Yes (built-in + third-party) Yes (built-in + third-party)
Storage S3-compatible Google Cloud Storage
Serverless functions Edge Functions (Deno) Cloud Functions (Node.js)
Open source Yes (self-hostable) No (proprietary)
Free tier 500MB DB, 50K MAU, 1GB storage 1GB Firestore, 10K DAU, 5GB storage
Pricing model Predictable (per resource) Usage-based (can spike)
Query language SQL (full SQL support) NoSQL queries (limited)
Self-hosting Yes (Docker) No
Vendor lock-in Low (standard Postgres) High (proprietary APIs)

Database Comparison: PostgreSQL vs Firestore

This is the single most important difference. Your database choice determines your data model, query flexibility, and migration difficulty.

Supabase PostgreSQL

Supabase gives you a full PostgreSQL database. You can run SQL queries, create complex joins, use transactions, define foreign keys, create stored procedures, and use advanced features like JSONB, full-text search, PostGIS for geo, and pgvector for AI embeddings.

-- Create tables with relations
CREATE TABLE authors (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE posts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  author_id UUID REFERENCES authors(id) ON DELETE CASCADE,
  title TEXT NOT NULL,
  content TEXT,
  published BOOLEAN DEFAULT FALSE,
  view_count INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Complex queries are easy
SELECT a.name, COUNT(p.id) as post_count, SUM(p.view_count) as total_views
FROM authors a
LEFT JOIN posts p ON p.author_id = a.id
WHERE p.published = TRUE
GROUP BY a.name
ORDER BY total_views DESC
LIMIT 10;

Firebase Firestore

Firestore is a NoSQL document database. Data is stored in collections and documents. There are no joins, no foreign keys, and no SQL. You design your data model around read patterns, often duplicating data.

// Add a document
import { db } from "./firebase-config";
import { collection, addDoc, getDocs, query, where } from "firebase/firestore";

// Create a post
const docRef = await addDoc(collection(db, "posts"), {
  authorId: "user-123",
  authorName: "Jane",  // duplicated - no joins in Firestore
  title: "My first post",
  content: "Hello world",
  published: true,
  viewCount: 0,
  createdAt: new Date(),
});

// Query posts by author (requires composite index)
const q = query(
  collection(db, "posts"),
  where("authorId", "==", "user-123"),
  where("published", "==", true)
);
const snapshot = await getDocs(q);
const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));

Database Feature Comparison

Feature Supabase (PostgreSQL) Firebase (Firestore)
Data model Relational (tables, rows) Document (collections, docs)
Schema Enforced (DDL) Flexible (no schema)
Joins Yes (unlimited) No
Transactions Yes (ACID) Limited (batch writes)
Foreign keys Yes No
Indexes B-tree, GIN, GiST, BRIN Composite (auto-created)
Full-text search Yes (built-in) No (need Algolia)
Geospatial Yes (PostGIS) No
AI vector search Yes (pgvector) No
JSON support JSONB (indexable) Native
Max record size Unlimited (practical: 1TB) 1MB per document
Max depth Unlimited 20 subcollections
Query complexity Unlimited (SQL) Limited (no OR, limited IN)
Real-time Postgres replication Native (onSnapshot)
Offline persistence No Yes (built-in SDK)
Consistency Strong (ACID) Strong (per document)

When PostgreSQL Wins

  • Your data is relational (users → orders → items)
  • You need complex queries with joins and aggregations
  • You need transactions across multiple tables
  • You want full-text search without a third-party service
  • You need strong schema enforcement
  • You want to use AI/vector search (pgvector)
  • You might need to migrate away from the BaaS (standard SQL is portable)

When Firestore Wins

  • Your data is naturally hierarchical and document-like
  • You need offline-first mobile apps (Firestore SDK handles this)
  • Your schema changes frequently and rapidly
  • You need real-time updates without configuring replication
  • Your team is less familiar with SQL
  • You want Google's global infrastructure and reliability

Pricing Comparison

Pricing is where Supabase and Firebase diverge significantly, especially at scale.

Supabase Pricing

Plan Monthly Cost Database Auth Storage Edge Functions Bandwidth
Free $0 500MB 50K MAU 1GB 500K invocations 5GB
Pro $25 8GB (+$0.125/GB) 100K MAU (+$0.0033/MAU) 100GB (+$0.021/GB) 2M invocations (+$2/million) 250GB (+$0.09/GB)
Team $599 8GB (+$0.125/GB) 100K MAU (+$0.0033/MAU) 100GB (+$0.021/GB) 2M invocations (+$2/million) 250GB (+$0.09/GB)
Enterprise Custom Custom Custom Custom Custom Custom

Firebase Pricing

Firebase has two pricing plans: Blaze (pay-as-you-go, with free tier) and Blaze (no free tier on some services).

Resource Free Tier Paid Pricing
Firestore storage 1 GB $0.108/GB/month
Firestore reads 50K/day $0.036/100K
Firestore writes 20K/day $0.108/100K
Firestore deletes 20K/day $0.012/100K
Authentication 50K MAU $0.01/MAU (50K-1M), $0.0025/MAU (1M+)
Cloud Storage 5 GB $0.026/GB/month
Storage operations 1 GB egress $0.12/GB egress
Cloud Functions 2M invocations $0.0000004/invocation + compute
Cloud Messaging Unlimited Free
Hosting 10 GB storage, 360 MB/day $0.026/GB storage, $0.15/GB egress

Real-World Cost Comparison

Let's compare costs for a typical SaaS app with 10,000 monthly active users, 5GB database, 10GB storage, and 1M API calls/month.

Resource Supabase Pro Firebase Blaze
Database/storage $25 (8GB included) Firestore: $0.54/mo (5GB)
Authentication $0 (100K MAU included) $0 (50K free) + $0 (next 50K free in some cases)
Storage $0 (100GB included) $0.13/mo (10GB)
Functions/API $0 (2M included) $0.40/mo (1M invocations)
Bandwidth $0 (250GB included) $1.80/mo (15GB egress)
Total $25/month ~$2.87/month

At small scale, Firebase is cheaper. But as your database grows and queries increase:

Scenario: 100K MAU, 50GB database, 50GB storage, 10M Firestore reads/month

Resource Supabase Team Firebase Blaze
Base plan $599 $0 (pay per use)
Database $0 (8GB included) + $5.25 (42GB extra) Firestore: $5.40/mo (50GB)
Firestore reads N/A (SQL, unlimited) $3.60/mo (10M)
Authentication $0 (100K MAU included) $0.50/mo (50K-100K)
Storage $0 (100GB included) $1.30/mo (50GB)
Bandwidth $0 (250GB included) $6.00/mo (50GB egress)
Total $604.25/month ~$16.80/month

Firebase can be cheaper at moderate scale because Firestore is very efficient for document reads. But there are scenarios where Firebase gets expensive:

Scenario: App that does 100M Firestore reads/month (e.g., real-time dashboard)

Resource Supabase Firebase
Database reads Unlimited (SQL) $36/mo (100M reads)
Total $25 (Pro) $36+ reads + other costs

And the killer Firebase scenario: egress bandwidth

Scenario: App serving 500GB of files/month

Resource Supabase Pro Firebase Blaze
Storage $0 (100GB included) $13.00/mo (500GB)
Egress $0 (250GB included) + $22.50 (250GB extra) $60.00/mo (500GB)
Total $47.50/month $73.00/month

Pricing Summary

Scenario Cheaper Option
Prototype / MVP Firebase (generous free tier)
Small app (< 50K users) Firebase
App with many DB reads Supabase (SQL is unlimited reads)
App with relational data Supabase
App with heavy egress Supabase (250GB included vs Firebase $0.12/GB)
App with real-time everywhere Firebase (native, cheap)
Enterprise with compliance Supabase (self-host, SOC2)

Authentication Comparison

Both platforms provide authentication, but with different approaches and feature sets.

Supabase Auth

Supabase provides GoTrue-based authentication with:

  • Email/password
  • Magic links
  • OAuth (Google, GitHub, Apple, Facebook, Twitter, Discord, Azure, etc.)
  • Phone OTP
  • SAML SSO (Team plan+)
  • Anonymous sign-in
  • Row Level Security (RLS) policies
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

// Sign up with email
const { data, error } = await supabase.auth.signUp({
  email: "user@example.com",
  password: "securepassword",
});

// Sign in with Google OAuth
const { data, error } = await supabase.auth.signInWithOAuth({
  provider: "google",
  options: { redirectTo: "https://yoursite.com/callback" },
});

// Get current session
const { data: { session } } = await supabase.auth.getSession();

// Row Level Security: restrict data access by user
// SQL policy:
-- CREATE POLICY "Users see own data" ON posts
-- FOR SELECT USING (auth.uid() = author_id);

Firebase Auth

Firebase Authentication provides:

  • Email/password
  • Email link (magic link)
  • OAuth (Google, Apple, Facebook, Twitter, GitHub, Microsoft, etc.)
  • Phone authentication
  • Anonymous auth
  • Custom claims
  • Multi-factor authentication
import { initializeApp } from "firebase/app";
import { getAuth, createUserWithEmailAndPassword, GoogleAuthProvider, signInWithPopup } from "firebase/auth";

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

// Sign up with email
const userCredential = await createUserWithEmailAndPassword(auth, "user@example.com", "securepassword");

// Sign in with Google
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);

// Security rules for Firestore
// rules_version = '2';
// service cloud.firestore {
//   match /databases/{database}/documents {
//     match /posts/{postId} {
//       allow read, write: if request.auth.uid == resource.data.authorId;
//     }
//   }
// }

Auth Feature Comparison

Feature Supabase Firebase
Email/password Yes Yes
Magic links Yes Yes
OAuth providers 20+ 10+
Phone OTP Yes Yes (paid)
Anonymous Yes Yes
SAML SSO Yes (Team+) No
MFA Yes Yes
RLS / Security rules SQL policies Firestore rules
Custom claims Yes (JWT) Yes (custom claims)
Session management JWT (5min refresh) ID token (1hr refresh)
Free tier MAU 50,000 50,000 (unlimited anonymous)

Real-time Comparison

Supabase Real-time

Supabase uses Postgres logical replication to broadcast database changes. Clients subscribe to table changes via WebSocket.

// Subscribe to changes on the posts table
const channel = supabase
  .channel("posts-changes")
  .on(
    "postgres_changes",
    { event: "*", schema: "public", table: "posts" },
    (payload) => {
      console.log("Change:", payload);
      if (payload.eventType === "INSERT") {
        // New post added
      }
    }
  )
  .subscribe();

// Cleanup
channel.unsubscribe();

Firebase Real-time

Firestore has native real-time. Every document query can be live-updated via onSnapshot.

import { collection, onSnapshot, query, where } from "firebase/firestore";

// Real-time listener on posts
const q = query(collection(db, "posts"), where("published", "==", true));
const unsubscribe = onSnapshot(q, (snapshot) => {
  snapshot.docChanges().forEach((change) => {
    if (change.type === "added") {
      console.log("New post:", change.doc.data());
    }
    if (change.type === "modified") {
      console.log("Modified:", change.doc.data());
    }
    if (change.type === "removed") {
      console.log("Removed:", change.doc.data());
    }
  });
});

// Cleanup
unsubscribe();

Real-time Comparison

Feature Supabase Firebase
Real-time method Postgres replication Native document sync
Latency ~100-200ms ~50-100ms
Max connections 200 (Free), 500 (Pro), unlimited (Team) 1M concurrent per DB
Selective sync Yes (filter by column) Yes (query-based)
Offline sync No Yes (built-in)
Presence Yes (broadcast API) Yes (real-time database)
Cost at scale Included in plan Free (reads count)
Setup complexity Low (one config) Zero (automatic)

Firebase's real-time is more polished and faster. Supabase real-time works but has more latency and connection limits on lower plans.

Storage Comparison

Feature Supabase Firebase
Backend S3-compatible Google Cloud Storage
Client SDK Yes (upload, download) Yes (upload, download)
Resumable uploads Yes Yes
Image transformation Yes (on-the-fly) No (needs separate service)
CDN Yes (global) Yes (Cloud CDN)
Free tier 1GB storage, 2GB egress 5GB storage, 1GB egress/day
Paid storage $0.021/GB $0.026/GB
Paid egress $0.09/GB $0.12/GB
Self-host Yes No
// Supabase storage upload
const { data, error } = await supabase.storage
  .from("avatars")
  .upload("user-123/avatar.png", file, {
    contentType: "image/png",
    upsert: true,
  });

// Get public URL
const { data: { publicUrl } } = supabase.storage
  .from("avatars")
  .getPublicUrl("user-123/avatar.png");

// Firebase storage upload
import { getStorage, ref, uploadBytes, getDownloadURL } from "firebase/storage";

const storage = getStorage();
const storageRef = ref(storage, "avatars/user-123/avatar.png");
await uploadBytes(storageRef, file);
const url = await getDownloadURL(storageRef);

Serverless Functions Comparison

Feature Supabase Edge Functions Firebase Cloud Functions
Runtime Deno (TypeScript) Node.js, Python, Go, Java
Location Global edge (35+ regions) Single region (or multiple)
Cold start ~5ms (edge) 500-2000ms (Node), 1-5s (Java)
Max execution 150 seconds 9 minutes (HTTP), 60 min (Cloud Tasks)
Max memory 128MB 32GB
Free tier 500K invocations 2M invocations
Paid pricing $2/M invocations $0.0000004/invocation + compute
Webhook support Yes Yes
Scheduled (cron) Yes (pg_cron) Yes (Cloud Scheduler)
Secrets management Yes (Vault) Yes (Secret Manager)

Supabase Edge Function Example

// supabase/functions/hello/index.ts
import { serve } from "https://deno.land/std/http/server.ts";

serve(async (req: Request) => {
  const url = new URL(req.url);
  const name = url.searchParams.get("name") || "World";

  return new Response(JSON.stringify({ message: `Hello, ${name}!` }), {
    headers: { "Content-Type": "application/json" },
  });
});

Deploy: supabase functions deploy hello

Firebase Cloud Function Example

// functions/index.js
const functions = require("firebase-functions");
const { onRequest } = require("firebase-functions/v2/https");

exports.hello = onRequest((req, res) => {
  const name = req.query.name || "World";
  res.json({ message: `Hello, ${name}!` });
});

Deploy: firebase deploy --only functions

Step-by-Step: Getting Started with Supabase

1. Create a Project

  1. Go to supabase.com
  2. Click "Start your project"
  3. Sign in with GitHub
  4. Click "New project"
  5. Name: my-app
  6. Database password: set a strong password
  7. Region: choose closest to your users
  8. Plan: Free
  9. Click "Create new project" (takes 2-3 minutes)

2. Create a Table

-- Go to SQL Editor and run:
CREATE TABLE tasks (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id),
  title TEXT NOT NULL,
  completed BOOLEAN DEFAULT FALSE,
  priority TEXT DEFAULT 'medium',
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Enable Row Level Security
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;

-- Policy: users can only see their own tasks
CREATE POLICY "Users manage own tasks" ON tasks
  FOR ALL USING (auth.uid() = user_id);

-- Enable real-time
ALTER PUBLICATION supabase_realtime ADD TABLE tasks;

3. Connect Your App

npm install @supabase/supabase-js
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  "https://YOUR_PROJECT.supabase.co",
  "YOUR_ANON_KEY"
);

// Create a task
const { data, error } = await supabase
  .from("tasks")
  .insert({ title: "Write blog post", user_id: userId })
  .select();

// Read tasks
const { data: tasks } = await supabase
  .from("tasks")
  .select("*")
  .eq("completed", false)
  .order("created_at", { ascending: false });

Step-by-Step: Getting Started with Firebase

1. Create a Project

  1. Go to console.firebase.google.com
  2. Click "Add project"
  3. Name: my-app
  4. Google Analytics: optional
  5. Click "Create project"

2. Create a Firestore Database

  1. Go to Build → Firestore Database → Create database
  2. Location: choose closest to users
  3. Mode: Production mode
  4. Click "Create"

3. Add a Collection

  1. Click "Start collection"
  2. Collection ID: tasks
  3. Add first document:
    • title: string
    • completed: boolean (false)
    • priority: string ("medium")
    • createdAt: timestamp

4. Set Security Rules

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /tasks/{taskId} {
      allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
      allow create: if request.auth != null;
    }
  }
}

5. Connect Your App

npm install firebase
import { initializeApp } from "firebase/app";
import { getFirestore, collection, addDoc, getDocs, query, where } from "firebase/firestore";

const firebaseConfig = {
  apiKey: "AIza...",
  authDomain: "my-app.firebaseapp.com",
  projectId: "my-app",
  // ... from project settings
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

// Create a task
const docRef = await addDoc(collection(db, "tasks"), {
  title: "Write blog post",
  userId: currentUser.uid,
  completed: false,
  priority: "medium",
  createdAt: new Date(),
});

// Read tasks
const q = query(
  collection(db, "tasks"),
  where("completed", "==", false),
  where("userId", "==", currentUser.uid)
);
const snapshot = await getDocs(q);
const tasks = snapshot.docs.map(d => ({ id: d.id, ...d.data() }));

Migration: Can You Switch?

From Firebase to Supabase

Supabase provides a migration tool:

  1. Go to Supabase Dashboard → Integrations → Firebase
  2. Enter your Firebase service account JSON
  3. Select collections to migrate
  4. Click "Migrate"
  5. Firestore documents become rows, with fields mapped to columns

This works for simple collections. Complex nested structures may require custom migration scripts.

From Supabase to Firebase

There is no official tool. You would need to:

  1. Export tables as JSON
  2. Transform relational data to documents (denormalize)
  3. Write a script to insert into Firestore
  4. Rebuild security rules from RLS policies

This is harder because relational → NoSQL requires denormalization.

Decision Framework

Question If Yes → If No →
Is your data relational? Supabase Either
Do you need SQL queries? Supabase Either
Do you need offline-first mobile? Firebase Either
Is real-time critical and fast? Firebase Either
Are you worried about vendor lock-in? Supabase Either
Do you need to self-host? Supabase Firebase
Is your team familiar with SQL? Supabase Firebase
Do you need AI/vector search? Supabase Firebase
Do you want the cheapest option at scale? Depends on usage Depends
Are you building a quick prototype? Either Either

Monetization Opportunities

Method Platform Income Potential
Build SaaS apps faster Either $1K-50K/month
Create templates/starters Supabase $200-2K/month (Gumroad)
Consulting and setup Either $50-150/hour
Tutorials and courses Either $500-5K/month
Firestore/Postgres optimization Either $100-300/hour

Action Checklist

  • Evaluate your data model (relational vs document)
  • Check if you need SQL queries and joins
  • Determine your real-time requirements
  • Estimate your expected reads/writes/egress
  • Try Supabase free tier (create project, run SQL)
  • Try Firebase free tier (create project, add collection)
  • Build a simple CRUD app on both platforms
  • Compare developer experience for your team
  • Check pricing for your expected scale
  • Evaluate vendor lock-in risk
  • Check for required features (SAML, vector search, offline sync)
  • Make your choice and commit
  • Design your schema/data model carefully
  • Set up security rules/RLS from day one
  • Monitor usage and costs in the dashboard

Common Pitfalls

Pitfall Platform Impact Solution
No RLS / open rules Both Data leak Set policies/rules before launch
Over-querying Firestore Firebase High costs Batch reads, cache locally
Not using indexes Supabase Slow queries Create indexes on filter columns
Deep nested collections Firebase Complex queries Flatten data model
No connection pooling Supabase Connection errors Use Supavisor (auto-pooled)
Large documents in Firestore Firebase 1MB limit Split into multiple docs
Not planning for scale early Both Expensive migration Choose based on 2x expected growth

Final Word

Supabase and Firebase are both excellent platforms, and the right choice depends on your data model and team. Choose Supabase if your data is relational, you need SQL queries and joins, you want to avoid vendor lock-in, or you need features like full-text search, PostGIS, or pgvector AI search. Choose Firebase if your data is document-oriented, you need offline-first mobile apps, your team prefers NoSQL, or you want the fastest real-time experience. Both platforms have generous free tiers: Supabase gives you 500MB PostgreSQL, 50K auth users, and 1GB storage; Firebase gives you 1GB Firestore, 50K MAU, and 5GB storage. Start with the free tier of whichever matches your data model, build a small CRUD app to test the developer experience, and scale up from there. For side hustles, both platforms let you build a complete backend in a weekend — auth, database, real-time, storage, and functions — without managing a single server.

More guides: bsynet.cc

Tags

#Supabase#Firebase#BaaS#Backend#Database

Related Posts