
Jurij Tokarski
· Updated
Why Is My Firebase Bill So High?
The bill jumped while traffic stayed flat. It's usually reads: listeners, rule lookups and polling. The fix sits in the data model, and Firebase can stay.
Our app has a few hundred daily users. Last month the Firebase bill jumped while traffic stayed flat. Is this normal, and should we move off Firebase?
Usually it's reads, not traffic. Under Firebase pricing, Firestore bills every document it reads. So the bill follows how the app reads its data, not how many people open it.
A flat traffic graph under a rising bill means each visit got more expensive. Something in the app now reads more documents per screen than it did the month before.
So the fix sits in the data model, and Firebase can stay. I learned that on my own bill first.
Reads Multiply Inside the App
A few hundred users don't cost a few hundred reads. Each screen reads again for every user, every time it opens, and three patterns do most of the reading:
- A listener on a whole collection reads every document it matches when the screen opens, then every change after.
- A rule that calls
get()orexists()adds a billed read on top of the read it guards. - A poll asks whether anything changed and pays for the answer, even when nothing did.
My RSS reader Fidder had two of them, with one user: me. In January 2025 it cost about $12 in Firebase.
Its rules ran lookups on every access: hundreds of billable reads a day to check that I could read my own feeds. A background worker polled for changes whether there were any or not.
I moved each user's data under their own path, so the rule became one line with no lookups. Then I swapped the polling for functions that run on database events. The Firestore bill fell from about $12 to under $1 a month.
The app in the question multiplies the same patterns by a few hundred users. The jump last month says one of them arrived recently, and the bill can say which.
Find the Collection That Costs the Most
Read the usage by day, then match it to the collections and screens that read it.
The billing report, grouped by SKU, splits the bill into Firestore reads, writes and deletes, function invocations, storage and network. Over a range of two months or less, it shows each day. So a bill that jumped in one month usually shows the day it jumped.
A day points at a release. What shipped that week is the first suspect: a new screen, a listener moved higher up, a rule that started reading another document.
The collection comes next. Every listener and query in the code names the collection it reads. So the biggest line maps to a short list of screens.
Once you find the screen, the next question is how to keep it from happening again.
A Budget Warns, It Doesn't Stop
Firestore has no hard billing cap. A budget on Google Cloud sends an email at the thresholds you set, and the meter keeps running.
Google has started adding spend caps to a few Firebase products, in preview: Cloud Functions, App Hosting, Extensions and AI Logic. Firestore isn't on that list.
A hard stop for Firestore takes a function that the budget triggers and that turns billing off for the project. It stops the bill and the app together, so it's a last resort, not a limit.
So part of the cap has to live in the code. A query with a limit, a listener on one page, a function that checks before it writes: each bounds what one screen can cost.
Rules came up twice already, as a cost. Their bigger job is deciding who reads anything at all.
The Key Is Public, the Rules Protect
A team reading its Firebase setup soon finds the API key in the browser code. That key isn't a leak on its own. Firebase web keys are public by design: the key names the project, and the rules decide what anyone can do with it.
So the test is the rules, and it fits in one question: can a signed-in stranger read or write what they shouldn't? In a Firebase web app the browser talks to Firestore directly, so nothing else stands in the way.
Firebase security rules usually fail in one of three ways:
- They were left open from setup, in a test mode meant to be temporary.
- They check only that a user signed in, which lets in anyone who can sign up.
- They fit the first collections and miss one added months later.
The safe shape is deny by default, then open each path to the user it belongs to. Data under the user's own path makes that one line, the same move that cut Fidder's bill. The Firebase emulator runs the rules locally, so a test can sign in as a stranger and try every path.
Other keys are a leak the moment they reach the browser. An OpenAI or Gemini key in frontend code lets anyone copy it and spend on the owner's account. I found that in an app sent to me for review, next to missing Firestore rules.
The AI calls move behind Cloud Functions, where the key stays on the server, and the old key gets rotated. A leaked AI key bills you too, and no data model fixes it.
Moving Off Doesn't Fix the Data Model
Sometimes moving is right. Postgres fits data that's heavily relational, where most screens join several tables and the reports need queries Firestore can't run.
More often the reads are the problem, and they move with the app. A screen that loads a whole collection to show one page does the same on Postgres. There the cost shows up as a bigger server and a slower page instead of a line per read.
Fidder stayed on Firebase. The data model changed, and the bill with it. Firebase sits in my default stack because one person can ship sign-in, data, files, functions and hosting on one bill.
The trade-off is real. Moving Fidder fully onto Firebase cost me protection from its pricing changes. Context over purity decides it per project: the shape of the data, the team, the credits.
For this team, fix the reads first, then decide the move on what's left. Should I rebuild my app from scratch? walks through the same choice for a whole app.
What One Screen Costs
Google's price list shows how fast a single screen adds up. In October 2026, Firestore's pricing page gave each project 50,000 free reads a day. After that, it charged $0.03 per 100,000 reads in its Iowa region.
Take a listener on a collection of 500 documents, opened five times a day, hours apart, by 300 users. That's 750,000 reads a day, about $6 a month from one screen, before a single change arrives.
The same screen with a limit of 20 reads 30,000 documents a day. That stays inside the free tier, and it's a ceiling no budget alert can set.
How I Run a Firebase Audit
Mine takes one week, with access to the Firebase project, its billing and the repo. Day one is the bill: each line traced to the query, listener or function behind it.
Then the data model and the rules. Every collection gets tested the way a hostile client would try it.
The week ends in a report and the top fix. The report says what I found, what each finding costs and what to fix first. It also lists the limits the app needs: which alerts, which caps, which queries need a ceiling. The plan is on my Firebase audit page, and the price is on the homepage.
After the report and the top fix, the rest run by the week, with me or with whoever you choose.
What the Team Should Do Now
This week, read the usage by day and match it to the collections in the code. Find the day the bill jumped and what shipped on it.
Then fix the one screen that reads the most. A limit on its query, a listener on one page or data under the user's path are the usual fixes. Next week's usage shows whether it worked.
While you're in the code, try the rules as a signed-in stranger and look for AI keys in the frontend. Moving off Firebase can wait until the reads are fixed.
If the bill won't trace to a screen, an audit traces it in a week.
A high Firebase bill is the easiest problem to read. It already lists what the app does too often.
Got thoughts on this? Reply by email.

Jurij Tokarski
I run a solo business and produce software. Usually I'm shipping for clients or building for myself. Sometimes I pause to write about it.