Stories

The Firebase bill that taught us to see

A runaway Firestore read bill sent us chasing ClickHouse. The real fix was not a new database — it was being able to see where every read came from. What we learned, and why we open-sourced Buckets.

Crossdeck

Summary

  • A Firestore bill is one big number with no itemisation — it never tells you why it is high.
  • Our first instinct was to reach for ClickHouse. That would have added a second system to feed without fixing the root cause.
  • The real culprit was scan-on-read: screens re-reading whole collections on every load.
  • You cannot optimise what you cannot attribute. So we built Buckets — an open-source meter that tags every read with its cause — and made it free for life.

The bill nobody could explain

Every team that builds on Firestore eventually gets the same surprise: a database bill that climbs faster than usage, arriving as a single opaque number. Reads are billed per document, and a modern app performs an enormous number of them — but the invoice never says which screen, which feature, or which user drove them.

Ours crept up the way these always do. A dashboard that felt instant was quietly performing hundreds of thousands of reads a day — because every time it loaded, it re-read entire collections to render a summary. Multiply that by every open tab and every active user, and the meter never stops spinning.

The uncomfortable part was not the amount. It was that nobody could point to the cause. We could see the total. We could not see the why.

Should you throw ClickHouse at a Firestore bill?

The reflex answer to “our database costs too much” is to add a cheaper analytical database — ClickHouse, BigQuery, an OLAP store — and move the heavy reads there. We seriously evaluated it. It is the move everyone recommends.

Here is what we concluded, and it is the first real lesson: a second database does not fix a read problem — it relocates it, and adds a system you now have to keep in sync. You are still doing the expensive work; you have just built a pipeline to feed a new engine, plus the drift, the lag and the maintenance that come with it. For genuine analytics workloads an OLAP store batched off your own ledgers is the right tool. But as a fix for a runaway operational bill, ClickHouse treats the symptom. The reads that were killing us were not analytics — they were a summary screen scanning a collection it should never have touched.

Reaching for a new database before you have attributed the cost is optimising blind. You will spend weeks moving data and still not know whether you solved the actual problem.

The real problem was not the database — it was the blind spot

When we finally traced it, the villain was mundane: scan-on-read. Surfaces were reading many documents on every render to compute something that should have been a single pre-computed read. The fix, once we could see it, was almost boring — mint the value on write, read one document on read. O(1) instead of O(collection). The bill fell off a cliff.

But notice the sequence. The fix was cheap. Finding it was expensive — because Firestore gives you the total and hides the breakdown.

You cannot optimise what you cannot attribute. The bill has to be itemised before any of the advice — indexes, caching, a new database — is safe to follow.

That gap — an opaque bill with no per-cause breakdown — is not unique to us. Every Firebase developer has it. So we built the thing we wished we had had on day one.

What Buckets is

Buckets is an open-source read-cost meter for Firestore. It turns the single opaque number into an itemised bill, tagging every read with where it came from — which surface or query — and who triggered it. Instead of “your bill is high”, you get “this screen is sixty per cent of it, this background job is the expensive one, and here is what each user actually costs to serve”.

It is the smart meter for a bill that previously arrived with no breakdown. Once you can see reads by cause, the optimisation becomes obvious. The hard part was never the fix. It was the visibility.

Why we open-sourced it

We could have kept Buckets internal. We did not, for two reasons.

First, the blind spot is universal. Anyone building on Firestore hits this wall, and a meter only earns trust if you can read the source. So Buckets is open source under an MIT licence and free for life — no account required to see your own cost breakdown.

Second, it reflects how we think across the portfolio: make the invisible legible. The most expensive problems in software are not the hard ones. They are the ones you cannot see. A tool that makes cost attributable is worth more than any single optimisation, because it makes every future optimisation safe to attempt. It is the same argument that produced Crossdeck, and Buckets is where it showed up first — in the least glamorous place imaginable, a database invoice.

What changed

After Buckets, cost stopped being a quarterly surprise and became a number we could point at. Expensive surfaces got flagged the moment they appeared, not three invoices later. And the discipline it forced — know the cause before you touch the code — turned out to be the actual product of the whole episode. The savings were welcome. Being able to see was the win.

See your Firestore reads, itemised.

Buckets is open source and free for life.

Questions people ask

Why is my Firebase bill so high?
Almost always because of read volume. Firestore bills per document read, and common patterns — re-reading whole collections to render a summary, un-paginated lists, background jobs that scan — multiply reads fast. The bill shows the total but not the cause, so the first step is attributing reads to the surface and actor driving them, not guessing.
Does ClickHouse or BigQuery reduce Firestore costs?
For true analytics workloads, an OLAP store batched off your data can help. But as a fix for a runaway operational bill it usually just relocates the cost and adds a system to keep in sync. Attribute the reads first — the real fix is often architectural, such as pre-computing on write and reading one document.
How do I see what is driving Firestore reads?
Use a read-cost meter that attributes each read to its cause. Buckets, which is open source, tags reads by surface and actor and turns the opaque bill into an itemised one, so you can see which screen, job or user is expensive before you optimise.
What is scan-on-read?
Reading many documents on every render to compute something that could be a single pre-computed value. It is one of the most common causes of a surprise Firestore bill, and the fix is to mint the value on write and read one document on read.
Is Buckets really free?
Yes. Buckets is open source under an MIT licence and free for life. You can see your own read-cost breakdown without an account.

Every product named here is built and operated by Cross Constellation.


The lesson

The savings were welcome. Being able to see was the win.

Read next

Why we built Crossdeck — and why every product we build helps test it
We thought the App Store Connect wait was the problem. The real problem was fragmentation — the same person scattered across a dozen disconnected tools. So we put one SDK and one customer timeline underneath everything we operate.

Every product is a test environment for the one beneath it
A habit tracker on the App Store, a link-in-bio product carrying anonymous global traffic, and a book catalogue on two platforms. None of them was built to test anything. That is exactly why they work as tests.

The email address you’re keying on is not the person
Why email is a fragile anchor for user identity, how keying on the wrong id forks one person into many records, and how an identity graph converges every key onto one canonical customer.

We got our connector rejected. It was the best product spec we received all year.
A marketplace review rejected our connector with roughly a dozen findings. Instead of a failure, it read like a spec — the exact definition of a production-grade third-party integration we would never have written ourselves.

The black box blinks: seeing App Review happen in your own data
App Review is a black box. Identity-joined session data reveals when a reviewer starts testing your build, where they connect from, and the exact path they walk — plus the line we will not cross.

Why Biotree needed Crossdeck Trust — and how we stopped the SEO spam farms
Public, indexed link-in-bio pages are a magnet for spam farms and bot signups. The attack Biotree faced, why the obvious defences backfire, and the signup firewall that stopped it without punishing real users.

Why we are building Crossdeck Sales
Cold outbound is miserable because the seller is blind. We were not — we already saw who landed, what they read, and why. So we are building the tool that turns that journey into outreach that lands.