Supabase and Firebase are the two most popular Backend-as-a-Service (BaaS) platforms, but they take fundamentally different approaches. Firebase is a proprietary Google platform built around NoSQL and a tightly integrated ecosystem. Supabase is an open-source alternative built on PostgreSQL that aims to give you the Firebase experience without the vendor lock-in.
At a glance
| Supabase | Firebase | |
|---|---|---|
| Founded | 2020 | 2011 (Google, 2014) |
| Open source | Yes (Apache 2.0 / MIT) | No (proprietary) |
| Database | PostgreSQL (relational, SQL) | Firestore (NoSQL, document) |
| Auth | Built-in (GoTrue) | Firebase Auth |
| Real-time | PostgreSQL LISTEN/NOTIFY via WebSockets | Firestore live queries / RTDB |
| Storage | S3-compatible object storage | Firebase Storage (GCS) |
| Functions | Edge Functions (Deno) | Cloud Functions (Node.js) |
| Self-hostable | Yes (Docker) | No |
| Free tier | 2 projects, 500MB DB, 1GB storage | Spark plan (generous limits) |
| Best for | SQL-first apps, structured data, open-source priority | Mobile apps, rapid prototyping, Google ecosystem |
Architecture: PostgreSQL vs NoSQL
Supabase: PostgreSQL at the core
Supabase wraps PostgreSQL with a RESTful API (PostgREST), real-time subscriptions (Realtime server), auth (GoTrue), storage (Supabase Storage), and edge functions (Deno). Every feature is a thin layer on top of a standard Postgres database — which means you can connect directly with psql, run migrations, use ORMs, and write raw SQL.
-- In Supabase you write real SQL
SELECT
users.name,
COUNT(orders.id) AS order_count,
SUM(orders.total) AS revenue
FROM users
LEFT JOIN orders ON orders.user_id = users.id
WHERE users.created_at > NOW() - INTERVAL '30 days'
GROUP BY users.id
ORDER BY revenue DESC;
Firebase: document-based NoSQL
Firebase's primary database is Firestore — a hierarchical, document-oriented NoSQL store. Data is organized into collections and documents. There is no SQL; queries are limited to a single collection (no cross-collection joins) and you must structure your data for the queries you need.
// Firebase Firestore — limited query capabilities
const ordersRef = db.collection('orders');
const snapshot = await ordersRef
.where('userId', '==', userId)
.where('status', '==', 'shipped')
.orderBy('createdAt', 'desc')
.limit(20)
.get();
Database comparison
| Feature | Supabase (Postgres) | Firebase (Firestore) |
|---|---|---|
| Query language | Full SQL | Firestore query API (no JOIN) |
| Joins | Native SQL joins | Must denormalize or do client-side |
| Transactions | ACID, full multi-table | Single-document and batch (limited) |
| Schema | Strongly typed, enforced | Schemaless (flexible but risky) |
| Indexes | Auto + custom | Auto + composite (must pre-define) |
| Full-text search | tsvector/tsquery built-in |
Requires Algolia/Typesense integration |
| Vector search | pgvector extension |
Not native |
| Relationships | Foreign keys, referential integrity | Manual, application-level |
| Migration tooling | SQL migrations (Supabase CLI) | No schema migrations |
| Max document/row size | 1GB per row | 1MB per document |
Key insight: if your data is relational (users → orders → products), Supabase wins decisively. If your data is naturally hierarchical and document-shaped (e.g. chat messages nested under conversations), Firestore can be simpler.
Authentication
Both platforms provide email/password, magic links, OAuth (Google, GitHub, Apple, etc.), and phone/SMS auth out of the box.
Supabase Auth
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(url, anon_key);
// Sign up
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'supersecret',
});
// OAuth (Google)
await supabase.auth.signInWithOAuth({ provider: 'google' });
// Get current user
const { data: { user } } = await supabase.auth.getUser();
Firebase Auth
import { getAuth, signInWithEmailAndPassword, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
const auth = getAuth();
// Email/password
await signInWithEmailAndPassword(auth, 'user@example.com', 'supersecret');
// OAuth
const provider = new GoogleAuthProvider();
await signInWithPopup(auth, provider);
// Get current user
const user = auth.currentUser;
Differences:
- Supabase uses JWT tokens stored in local storage; Firebase uses its own token system with an SDK.
- Supabase Row Level Security (RLS) policies use
auth.uid()directly in SQL — very powerful for database-level security. - Firebase Security Rules are a separate DSL that can feel verbose for complex data shapes.
Row Level Security vs Firebase Security Rules
This is where Supabase truly shines for data-heavy apps.
Supabase RLS (SQL-based)
-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Users can only read their own posts
CREATE POLICY "Users can view own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);
-- Users can insert their own posts
CREATE POLICY "Users can insert own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
Firebase Security Rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read, write: if request.auth != null
&& request.auth.uid == resource.data.userId;
}
}
}
Supabase RLS rules live in the database itself and apply to every access path — REST API, direct SQL, and realtime subscriptions. Firebase rules apply to SDK access but not to Admin SDK calls (which bypass rules entirely).
Real-time subscriptions
Supabase Realtime
Supabase uses PostgreSQL's logical replication to stream database changes over WebSockets.
// Subscribe to all changes on the posts table
const channel = supabase
.channel('public:posts')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => {
console.log('Change received:', payload);
}
)
.subscribe();
// Broadcast (like a chat room, ephemeral)
const room = supabase.channel('chat-room');
room.on('broadcast', { event: 'message' }, ({ payload }) => {
console.log(payload);
});
room.subscribe();
Firebase Firestore Real-time
import { onSnapshot, collection, query, where } from 'firebase/firestore';
const q = query(collection(db, 'posts'), where('authorId', '==', userId));
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') console.log('New doc:', change.doc.data());
});
});
Key differences:
- Firebase Firestore real-time is battle-tested and used at scale by thousands of apps.
- Supabase Realtime is newer and has had scaling improvements; it works well but is less mature.
- For presence (who's online), Supabase Realtime Presence is excellent; Firebase RTDB is the classic choice.
Storage
Both offer file storage with direct upload from the browser.
| Feature | Supabase Storage | Firebase Storage |
|---|---|---|
| Backend | S3-compatible (MinIO self-hosted) | Google Cloud Storage |
| Access control | RLS-integrated storage policies | Firebase Security Rules |
| Transforms | Image resize/crop/webp on the fly | Requires Cloud Functions |
| CDN | Via Cloudflare (hosted) | Google CDN |
| Direct upload | Signed URLs, presigned uploads | Firebase SDK or signed URLs |
// Supabase Storage upload
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${userId}/avatar.jpg`, file, { upsert: true });
// Get public URL
const { data: { publicUrl } } = supabase.storage
.from('avatars')
.getPublicUrl(`${userId}/avatar.jpg`);
// Firebase Storage upload
import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage';
const storage = getStorage();
const storageRef = ref(storage, `avatars/${userId}/avatar.jpg`);
await uploadBytes(storageRef, file);
const url = await getDownloadURL(storageRef);
Serverless functions
| Feature | Supabase Edge Functions | Firebase Cloud Functions |
|---|---|---|
| Runtime | Deno (TypeScript) | Node.js / Python |
| Deploy speed | Fast (edge deploy ~30s) | Slower (2+ minutes) |
| Cold starts | Low (edge, globally distributed) | Can be significant (Node.js) |
| Triggers | HTTP, webhooks, database hooks (2024+) | HTTP, Firestore events, Auth events, Pub/Sub, Scheduler |
| Ecosystem | npm imports via CDN / JSR | Full npm ecosystem |
| Testing locally | supabase functions serve |
Firebase Emulator Suite |
| Pricing | 2M invocations/month free | 2M invocations/month free (Blaze plan) |
Firebase wins on trigger variety; Supabase wins on cold start performance.
Pricing comparison
Free tiers
| Resource | Supabase Free | Firebase Free (Spark) |
|---|---|---|
| Projects | 2 (paused after 7 days inactivity) | 1 project |
| Database | 500MB Postgres | N/A (charged per read/write) |
| Firestore reads | N/A | 50k/day |
| Firestore writes | N/A | 20k/day |
| Auth users | 50,000 MAU | Unlimited |
| Storage | 1GB | 5GB |
| Function invocations | 500K/month | 2M/month |
| Bandwidth | 5GB | 10GB/month |
Paid tiers
Supabase Pro starts at $25/month for 2 projects with 8GB database, 100GB storage, 250GB bandwidth.
Firebase pricing is usage-based with no fixed monthly fee — it can be cheaper at low scale but becomes unpredictable at high read/write volumes. A busy Firestore app can generate surprisingly large bills.
Key insight: Firebase's usage-based model can be dangerous for viral apps. Supabase's fixed pricing is more predictable for production workloads.
Open source and self-hosting
| Supabase | Firebase | |
|---|---|---|
| Open source | Yes (all components on GitHub) | No |
| Self-hostable | Yes (Docker Compose, Kubernetes) | No |
| Vendor lock-in | Low (standard Postgres underneath) | High (proprietary SDK, Firestore format) |
| Data portability | Easy (pg_dump) | Harder (Firestore export to JSON) |
| Community | Growing (65k+ GitHub stars) | Large but proprietary |
# Self-host Supabase with Docker
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env
# edit .env with your secrets
docker compose up -d
Where Supabase wins
| Scenario | Why Supabase |
|---|---|
| Relational data | SQL joins, foreign keys, referential integrity |
| Complex queries | Aggregations, CTEs, window functions |
| AI/vector search | pgvector extension built-in |
| Open source priority | Apache 2.0 licensed, self-hostable |
| Predictable costs | Fixed monthly pricing |
| Existing Postgres experience | No new query language to learn |
| Full-text search | Native tsvector/tsquery |
| Data migrations | SQL migration files, version-controlled |
| Compliance/GDPR | Self-host in your own region/cloud |
Where Firebase wins
| Scenario | Why Firebase |
|---|---|
| Mobile apps (Android/iOS) | Mature SDKs, offline support (Firestore) |
| Google Cloud ecosystem | Native integration with GCP, BigQuery |
| Offline-first apps | Firestore offline persistence is best-in-class |
| Rapid prototyping | No schema to define, just write documents |
| Push notifications | FCM (Firebase Cloud Messaging) is the standard |
| Analytics | Firebase Analytics, Crashlytics, A/B Testing |
| A/B testing & Remote Config | No equivalent in Supabase |
| Large ecosystem maturity | Firebase has been production-tested for 10+ years |
| Firestore scale | Automatic multi-region replication, 1M+ concurrent |
Code example: building a todo app
Supabase
// supabase/types.ts (auto-generated)
type Todo = { id: number; text: string; done: boolean; user_id: string };
// Fetch todos (RLS enforces user_id = auth.uid())
const { data: todos } = await supabase
.from('todos')
.select('*')
.order('created_at', { ascending: false });
// Insert
await supabase.from('todos').insert({ text: 'Buy milk', user_id: user.id });
// Update
await supabase.from('todos').update({ done: true }).eq('id', todoId);
// Real-time subscription
supabase
.channel('todos')
.on('postgres_changes', { event: '*', schema: 'public', table: 'todos' }, handleChange)
.subscribe();
Firebase
// Fetch todos (Security Rules enforce uid == userId)
const todosRef = collection(db, 'users', user.uid, 'todos');
const snapshot = await getDocs(query(todosRef, orderBy('createdAt', 'desc')));
const todos = snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
// Add
await addDoc(todosRef, { text: 'Buy milk', done: false, createdAt: serverTimestamp() });
// Update
await updateDoc(doc(todosRef, todoId), { done: true });
// Real-time
const unsubscribe = onSnapshot(todosRef, (snapshot) => {
const todos = snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
setTodos(todos);
});
Full comparison
| Feature | Supabase | Firebase |
|---|---|---|
| Database model | Relational (PostgreSQL) | Document (Firestore) + RTDB |
| Query power | Full SQL, joins, CTEs | Limited, no cross-collection joins |
| Transactions | Full ACID | Single-doc + batched writes |
| Schema | Strict + typed | Flexible (schemaless) |
| Auth | GoTrue (JWT) | Firebase Auth |
| Social login providers | 20+ | 20+ |
| Real-time | Postgres LISTEN/NOTIFY | Firestore live queries |
| Offline support | No (coming) | Yes (Firestore SDK) |
| Storage | S3-compatible | Google Cloud Storage |
| Image transforms | Yes (built-in) | Via Cloud Functions |
| Serverless | Edge Functions (Deno) | Cloud Functions (Node/Python) |
| Triggers | HTTP + DB hooks | HTTP + many event types |
| Open source | Yes | No |
| Self-hostable | Yes | No |
| Vendor lock-in | Low | High |
| Free tier | 500MB Postgres | Per-read/write model |
| Pricing model | Fixed monthly | Usage-based |
| Predictable costs | Yes | Can spike unexpectedly |
| Push notifications | Via third party | FCM (best-in-class) |
| Analytics | Via third party | Firebase Analytics |
| A/B testing | Via third party | Remote Config |
| TypeScript types | Auto-generated from schema | Manual or converters |
| Local development | Supabase CLI + local Docker | Firebase Emulator Suite |
| Postgres extensions | Yes (pgvector, PostGIS, etc.) | N/A |
| GitHub stars | 65k+ | N/A (proprietary) |
Decision guide
Do you need SQL / relational data or complex queries?
└─ Yes → Supabase
Do you need Firestore offline persistence on mobile?
└─ Yes → Firebase
Do you need push notifications (FCM)?
└─ Yes → Firebase (use FCM regardless of BaaS)
Is open source / self-hosting required?
└─ Yes → Supabase
Are you already in the Google Cloud / GCP ecosystem?
└─ Yes → Firebase (native integrations)
Do you want predictable, fixed monthly pricing?
└─ Yes → Supabase
Do you need AI / vector search (pgvector)?
└─ Yes → Supabase
Are you building a document-heavy mobile app with offline first?
└─ Yes → Firebase
Are you a SQL developer moving to BaaS?
└─ Yes → Supabase (familiar paradigm)
Default for new web SaaS projects → Supabase
Default for mobile + Google ecosystem → Firebase
Common mistakes
| Mistake | Better approach |
|---|---|
| Using Firebase Firestore for highly relational data | Switch to Supabase Postgres |
| Ignoring Supabase RLS — using service role key in the browser | Always use anon key + RLS policies |
| Not pre-defining Firestore indexes for compound queries | Add composite indexes before production |
| Forgetting Firebase pricing caps on Spark plan | Move to Blaze plan before you need it |
| Fetching entire Firestore collections for aggregations | Use Firestore aggregation queries (2023+) or Cloud Functions |
| Storing binary blobs in Firestore documents | Use Firebase Storage / Supabase Storage instead |
| Not setting up Supabase pausing (free tier projects pause after 7 days) | Upgrade or ping the project periodically |
| Using Firebase Admin SDK in client code (bypasses security rules) | Use Admin SDK only in server/Cloud Functions |
FAQ
Can I migrate from Firebase to Supabase? Yes, but it takes effort. Export Firestore data as JSON, then transform and import it into Postgres. Auth users can be exported from Firebase and imported via Supabase's admin API. File storage is a direct copy. There's no automated migration tool as of 2025, but the community has shared scripts.
Can I use both Supabase and Firebase in the same project? Yes. A common pattern is Supabase for the relational database and Firebase Cloud Messaging (FCM) for push notifications — FCM is best-in-class and has no direct Supabase equivalent.
Is Supabase production-ready? Yes. Supabase GA (Generally Available) was announced in 2023. Companies like Pebblely, Quivr, and many others run production workloads. However, Firebase has a longer track record at extreme scale.
Does Supabase work with React Native / mobile?
Yes. The @supabase/supabase-js SDK works in React Native with AsyncStorage. Offline support is limited compared to Firestore's built-in offline persistence.
What about Next.js or Remix — which BaaS integrates better?
Both integrate well with Next.js/Remix. Supabase has first-class Next.js App Router support via @supabase/ssr. Firebase has a Next.js SDK as well. For server components and server-side rendering, Supabase's SQL-backed approach is often simpler to reason about.
Is Firebase going away? No signals from Google suggest Firebase is being deprecated. However, Google has a history of sunsetting products (Firebase RTDB is in maintenance mode, replaced by Firestore). Supabase's open-source model means you're not dependent on a single vendor's roadmap.