The Day Firebase Costs Went Insane
February invoice was over three grand. Previous month was like $180, maybe $200. I stared at this shit for twenty minutes thinking we got cryptojacked or someone was running crypto miners through our chat feature. Nope, just users actually using the app we built.
The Firebase Cost Problem: Real-time listeners go fucking nuts reading way more data than you expect. Every user connection triggers document reads, and every data change forces re-reading entire result sets for all connected clients.
Turns out all our real-time listeners were going absolutely crazy, reading way more data than we expected. Firebase charges you more the more successful you get, which is backwards as hell. Seriously, check out this Firebase billing horror story from 2 days of usage.
That was the wake-up call. Time to figure out what else is out there.
The NoSQL Hell We Built Ourselves
Here's what nobody tells you about Firebase: starts great, turns into a horror movie.
We started simple - users, posts, comments. Typical shit. Two years later I'm looking at a user's name scattered across 14 different collections because Firebase can't do relationships worth a damn.
User changes their name from "John" to "Johnny"? Hope you remembered to update it in posts, comments, notifications, analytics, user_profiles, group_members, activity_feed, user_settings, and six other places. Miss one? Congratulations, your app now shows "Johnny" in the header and "John" in the comments. Users love that shit.
PostgreSQL just laughs at this problem. Foreign keys, joins, constraints - you know, the shit databases have been doing since the 90s.
SQL vs NoSQL Reality: In Firebase, updating a user's name means hunting down 12+ collections and hoping you don't miss any. In PostgreSQL, you update one table and foreign keys handle the rest automatically.
Firebase Security Rules: The Seventh Circle of Hell
Our Firebase security rules file is like 800+ lines of pure terror. Nobody on the team will touch it. Someone tried to add permissions for the reporting feature and accidentally locked out all admins because one nested condition was backwards.
Every rule change is Russian roulette with your production database.
Technical Gotcha: Firebase security rules have a 256KB size limit and 10-depth nesting limit. Hit both limits multiple times debugging complex permission hierarchies.
// This is actual production Firebase rules code that nobody dares touch
allow read, write: if request.auth != null
&& resource.data.teamId in request.auth.token.teamIds
&& (request.auth.uid == resource.data.createdBy
|| request.auth.token.admin == true
|| exists(/databases/$(database)/documents/teams/$(resource.data.teamId)/members/$(request.auth.uid)))
&& request.resource.data.keys().hasAll(['title', 'createdBy', 'teamId'])
&& request.resource.data.title.size() > 0
&& request.resource.data.title.size() <= 100;
Meanwhile in PostgreSQL, Row Level Security does the same thing in like 3 lines of readable SQL.
The Breaking Point
The final straw wasn't even the money. It was trying to build a simple analytics dashboard for our CEO.
"How many posts were created last week?"
Firebase: Read all posts. Filter client-side. Hope your lambda doesn't timeout. Cache the results. Build a whole microservice for counting. Maybe sacrifice a goat.
PostgreSQL: SELECT COUNT(*) FROM posts WHERE created_at > now() - interval '7 days'
I rage-quit that day and started researching Supabase.
Real-Time Features That Cost Real Money
Firebase's real-time stuff is slick, I'll give them that. But holy shit is it expensive.
Every time someone opens your app, boom - another listener. Every time data changes, boom - reread everything for everyone. Our notification system was reading the same data thousands of times per day because Firebase has to re-fetch entire result sets when connections drop.
Supabase's real-time is built on PostgreSQL's native features, so you're not getting gouged for basic database operations.
Why We Actually Started Looking at Alternatives
Look, Firebase isn't terrible. It's great for simple apps, prototypes, or if you're building something that doesn't need complex queries. But we hit these walls:
- Costs became unpredictable - One viral post could bankrupt us
- Data modeling became a nightmare - NoSQL felt like coding with one hand tied behind our back
- Security rules turned into spaghetti code - Nobody dared touch them
- Analytics were impossible - Want to count users? Good fucking luck
The moment I knew we were fucked was when implementing "most popular posts this week" took someone on the team three full days. Three fucking days! In PostgreSQL it's literally ORDER BY like_count DESC LIMIT 10
. In Firebase it's cloud functions, denormalized data, scheduled aggregations, and praying nothing breaks.
That's when I started the migration planning.
Next up: what actually happens when you try to migrate this mess.