Supabase vs Firebase
Fifty users watching a hundred documents that change twenty times a minute cost about $1,296 a month in Firestore reads, and a flat $25 on one Supabase Pro Micro project. The screen is identical; the only thing that changed is what the vendor counts.
If your bill grows with how often people watch data rather than how much data you keep, Supabase wins: that dashboard is about $1,296/month of Firestore reads against $25 for one Pro Micro project. If your app fits Firestore's daily free quota of 50,000 reads, 20,000 writes and 20,000 deletes, stay where you are, because leaving costs a schema project and a password path the migration repo still marks incomplete.
- The billing unit decides what code you may write
- A listener is a meter, not a subscription
- On Supabase the ceiling is capacity, not a per-read meter
- Index entry reads are the Firestore line item nobody quotes
- Migration is a schema project with a script attached
- Pick by bill shape first, then by blockers
- Cost arithmetic
- Decision matrix
- Migration path
- FAQ
At a glance
| Dimension | Supabase Open source | Firebase Managed Google |
|---|---|---|
| Product foundation | PostgreSQL (relational + pgvector) | Firestore (NoSQL document store) |
| Pricing model | Free: 500 MB, 2 projects · Pro $25 + $10/project compute | Daily free quota · reads $0.03 / writes $0.09 per 100k |
| Hosting and deployment | Yes (Docker stack) | No (proprietary GCP) |
| Runtime and integration | Postgres Changes (CDC, row-level-security aware) | Snapshot listeners — a read per changed document |
| AI-related capabilities | pgvector in the same database as your app data | kNN vector search, billed per 100-entry index batch |
| Lock-in risk | Low: standard Postgres, dump and leave | High: rules, SDKs, and no SQL export path |
| Vendor | Supabase → | Firebase → |
1. The billing unit decides what code you may write
Supabase sells a machine. You rent a Postgres instance, a disk and a connection ceiling, and reads inside them are free. Firebase sells events. Every document read, write, index batch and listener update is a line on the invoice, with a daily free quota on top.
What each philosophy forbids:
- Firestore forbids JOINs. A relation becomes duplicated fields or an extra round trip, and the extra reads are billed.
- Supabase forbids cheap concurrency. The $10 Micro instance stops at 60 direct and 200 pooled connections. The ceiling is purchasable rather than absolute — 12,000 pooled connections at $3,730 — but you buy it per project.
| Meter | Unit price | Pattern it punishes |
|---|---|---|
| Firestore reads | $0.03 / 100,000 | Live listeners on hot documents |
| Firestore writes | $0.09 / 100,000 | Per-keystroke saves, chatty counters |
| Supabase disk | $0.125/GB over 8 GB | Keeping everything forever |
| Supabase compute | $10 to $3,730/month per project | Many connections, many projects |
2. A listener is a meter, not a subscription
A listener is not a free subscription. Firestore bills a read each time a document enters or updates in a live listener's result set, and one more when a change pushes it out. The meter runs while nobody clicks. Don't pick Firestore for a screen that stays open all day.
Take 50 users, each watching 100 documents that change 20 times a minute:
users, docs, changes_per_min = 50, 100, 20
reads = users * docs * changes_per_min * 60 * 24 * 30
print(reads) # 4.32B events, zero clicks
print(reads / 100_000 * 0.03) # 43,200 x $0.03, before free quota
That is a gross read charge at the us-central1 rate, before free-quota adjustments. One Pro Micro project costs $25/month inside its quotas — which says nothing about whether that instance can carry the load, only that the bill stops tracking the watching. Reconnects make it worse:
- Offline persistence off: every reconnect is billed like a brand-new query.
- Persistence on but disconnected for more than 30 minutes: same bill.
3. On Supabase the ceiling is capacity, not a per-read meter
Postgres Changes is a database event stream, and you opt in per table:
Add a table to the publication:
alter publication supabase_realtime add table your_table_name;
Nothing in that stream is metered per read. What runs out is the instance: its compute tier and its connection and pooler limits. Compute is billed per project, separately from the plan.
| Compute | Monthly compute | Direct / pooled database connections |
|---|---|---|
| Micro | $10 | 60 / 200 |
| Small | $15 | 90 / 400 |
| Medium | $60 | 120 / 600 |
| Large | $110 | 160 / 800 |
| XL | $210 | 240 / 1,000 |
| 16XL | $3,730 | 500 / 12,000 |
You stop paying for spikes and start paying for headroom. Size for peak connections: Pro's $10/month credit covers one Micro, and every extra project adds its own compute.
4. Index entry reads are the Firestore line item nobody quotes
- One read per batch of up to 1,000 index entries a query reads.
- A query with one range field pays nothing for index entries. Zero range fields are also exempt. Add a second range field and billing starts.
count(),sum()andavg()bill index reads, with a 1-document-read minimum even at zero entries.
Firestore's own docs give the example: count() over 1,500 index entries bills 2 document reads.
Ten million plain reads cost $3.00 at the listed rate. The
count()in your page header is a different bill.
Audit any query that combines two range fields before it ships.
5. Migration is a schema project with a script attached
supabase-community/firebase-to-supabase on GitHub is community tooling, not an official CLI. What it does:
firestore2json.jsexports a collection;json2supabase.jsloads it into a table. One collection, one table.- Fields are flattened to
text,numeric,booleanorjsonb. - Splitting nested JSON into related tables needs custom hooks you write.
Auth is the sharper edge. firestoreusers2json and import_users move users, importing hashes with Firestore's SCRYPT parameters (base64_signer_key, base64_salt_separator, rounds, mem_cost).
Verifying an existing Firebase password on first login needs a middleware the repo itself marks work in progress. The AWS Lambda variant is listed as TBD.
Until that middleware exists, plan for blocked logins at cutover and decide in advance whether you force a password reset.
6. Pick by bill shape first, then by blockers
Choose Supabase when modeled Firestore charges exceed the plan and compute cost and the workload fits the selected tier and quotas. Keep Firestore when all free allowances fit:
- 50,000 reads, 20,000 writes and 20,000 deletes per day.
- 1 GiB stored, 10 GiB/month outbound; one free database per project.
Check today, in this order:
- Multiply listeners × documents per listener × changes per minute × (60 × 24 × 30) minutes, then × $0.03 per 100,000.
- Find every hot-path query with two range fields or a
count(). - On Supabase, compare peak database connections to Micro's 60 direct / 200 pooled.
- Check whether first-login existing-password verification blocks migration.
Cost arithmetic at volume
These are computed from the published unit prices, not measured. Each row prints its own formula, so you can replace our assumption with your traffic and redo it.
Decision matrix
Rows are the situation you are actually in. Pick the row before you read the pricing page again.
| If this is you | Take | Because |
|---|---|---|
| Live dashboard whose modeled Firestore charges exceed Supabase costs, within the selected tier and quotas | Supabase | One Pro Micro project costs $25/month within included quotas after the compute credit; listener updates count as Firestore reads. Check capacity separately. |
| Quiet app within every relevant Firestore free allowance | Firestore | Stay when reads, writes, deletes, stored data and outbound transfer all fit: 50,000 reads, 20,000 writes and 20,000 deletes daily, 1 GiB stored, 10 GiB/month outbound and one free database per project. |
| Relational reporting requiring JOINs, with migration schema work accepted | Supabase | Firestore has no JOINs. Supabase supports SQL JOINs; splitting nested JSON into related tables during migration requires custom hooks. |
| Offline app whose Firestore usage and reconnect charges fit its budget | Firestore with offline persistence on | With persistence off, every Firestore reconnect is billed like a brand-new query. With it on, disconnections longer than 30 minutes trigger that billing. |
| Database connection demand fits 16XL and its cost fits the budget | Supabase | 16XL offers 500 direct / 12,000 pooled database connections at $3,730/month compute, separately from the plan; larger sizes are available by request. |
| Agency whose verified total Firestore usage charges are lower than the Supabase setup | Firestore | Compare client workloads against the $35/month Pro total for 2 Micro projects within included quotas. Every extra Supabase project adds its own compute line, $10 for each Micro. |
| Existing Firebase password verification at first login is required, but its migration dependency is unresolved | Stay on Firebase | First-login verification of Firebase passwords depends on middleware the migration repo marks work in progress. |
| Aggregate-call charges remain below the Supabase setup cost | Firestore | Firestore's count() bills index reads on every call, with a 1-document-read minimum. A count over 1,500 index entries bills 2 document reads; compare call volume at $0.03 per 100,000 reads against $25/month for one Supabase Pro Micro project within included quotas. |
Code and configuration
// Relational read in one round trip. Free-tier note:
// the nested select is a JOIN, so 50 comments cost 0 extra reads.
const { data, error } = await supabase
.from('posts')
.select('id, title, comments(id, body, user_id)')
.eq('published', true)
.order('created_at', { ascending: false })
.limit(20);
// Here it breaks: anon key + missing RLS policy = empty array, not an error.
if (error) throw error;
// N+1 by design: comments are a second query per post.
const q = query(collection(db, 'posts'), where('published', '==', true));
const snap = await getDocs(q); // 20 reads
for (const doc of snap.docs) {
// Denormalise, or pay: 20 more queries = 20 more billed reads
const comments = await getDocs(collection(doc.ref, 'comments'));
}
// Here it breaks: a live listener on this collection bills a read on
// every document update, for every listener, for as long as the tab is open.
What you gain, what you give up
Supabase
- One invoice for compute, disk and connections — reads inside the instance are not metered
- pgvector lives in the same Postgres as your rows, so RAG needs no second system
- Standard Postgres: SQL, JOINs, transactions, triggers, and pg_dump as an exit door
- The connection ceiling is purchasable: 200 pooled connections on $10 Micro up to 12,000 on $3,730
- You buy headroom, not usage: peak connections decide the tier, and idle capacity still bills
- Every extra project adds its own compute line ($10 for a Micro) even on one Pro plan
- Free projects are paused after a week of inactivity, which kills demo and staging projects
- Realtime subscriber capacity is not on the price sheet; you size by connection and compute limits
Firebase
- Offline persistence and multi-platform SDKs that work when the network does not
- No connection pool to size: events are metered, not sockets
- A daily free quota of 50,000 reads and 20,000 writes per project
- Listeners bill only for documents that change in the result set, not for every poll
- A dashboard left open all day is a recurring read charge: 50 users can pass $1,296/month
- Reconnects are billed like brand-new queries — with persistence off, every one of them
- Index entry reads are a second meter: a second range field starts billing
- No JOIN, and the export tool flattens one collection to one table, so schema design lands on you
Migration path
supabase-community/firebase-to-supabase is community tooling, not an official CLI. firestore2json.js exports one collection, json2supabase.js loads it into one table, and fields are flattened to text, numeric, boolean or jsonb — splitting nested JSON into related tables is a hook you write. Auth is the harder half: firestoreusers2json and import_users carry passwords over as SCRYPT hash parameters, and verifying a user's existing Firebase password on first login needs middleware the repo still marks work in progress. Budget the schema work, not the script.
Common questions
Sources & verification
Prices and limits were read from these pages on 2026-11-10. Vendor marketing claims are quoted as claims. Anything derived is arithmetic on the numbers below.
https://supabase.com/pricing
https://supabase.com/docs/guides/realtime/postgres-changes
https://firebase.google.com/docs/firestore/pricing
https://cloud.google.com/firestore/pricing
https://supabase.com/kb/guides/migrate-from-firestore-data
Keep reading
Vercel vs Cloudflare Pages
The same penalty-table reading, applied to hosting: which line your workload inflates.
Notion vs Obsidian
Another free tier that is really a history and API budget.