FirestoreCloud costsLessons learned

How a Status Page Drove Firestore Costs Toward $2,300 in 30 Days

A status page that cost us $2.17 in its first 22 hours was on track to cost about $2,300 over its first 30 days — and $9,200 by day 60. The problem was a tiny Firestore design mistake that got more expensive every minute it ran. All figures are in AUD.

$2.17Day 1 (actual)
$2,300By day 30
$9,200By day 60
$0$2.5k$5k$7.5k$10k015304560 $2.17 · day 1$2,300 · day 30$9,200 · day 60 Days the status page had been running
Estimated cost if we hadn't fixed it. Double the days, four times the cost.

That number is small only because we caught it on day one. Left alone, the same page would have cost about $2,300 by day 30 and $9,200 by day 60. The monthly bill wasn't growing in a straight line. It was growing with the square of the uptime.

What normal looked like

Before the status page, the whole project ran at about 1,440 Firestore reads a day. That's well inside Firestore's free 50,000 reads a day, so the reads cost nothing. Nobody looks at a bill like that.

What happened after launch

  • 30 April (launch, late in the day): 72,010 reads.
  • 1 May: 2,645,285 reads, $2.17. By the time we fixed it, the page was doing about 4,000 reads a minute, and climbing.

A 1,800-fold jump in one day. And it was still accelerating.

Why it grew so fast

The status page showed a monthly uptime percentage. To keep that number fresh, it was recalculated every minute, and each recalculation re-read every sample ever collected.

So the cost of one recalculation grew with the history. Minute 1 read a handful of samples. Minute 1,000 read a thousand. Add up every minute and the total grows with the square of the time the page has been running.

That's why day one looked cheap and day 30 didn't:

Running forApprox. readsApprox. cost
1 day2.6 million$2.17
30 days2.8 billion$2,300
60 days—$9,200

Doubling the time quadruples the cost.

The fix

We stopped re-reading history. Now a counter is updated as each sample lands, and the uptime percentage is worked out from the counter. Nothing goes back through old samples.

After the fix, the project settled at about 1,670 reads a day, which is still inside the free quota. That's barely above where it was before the status page existed.

What founders should take from this

  1. Watch the shape of the cost, not the size. $2.17 looked like nothing. The problem was that it grew faster every day it ran.
  2. Anything that re-reads “everything so far” gets more expensive every time it runs. Totals, averages, percentages, leaderboards: keep a running count instead of recalculating from scratch.
  3. Check the bill the day after a launch. We caught this within a day because we looked. A monthly invoice would have shown up at around $2,300.

One honest caveat

The “22 hours” is worked out from the daily read counts, not taken from a deploy log. Billing only reports by the day. Getting an hour-by-hour picture would have needed the BigQuery billing export, and we didn't have it switched on. (That's worth switching on before you need it.)

The bug in this story cost $2.17 because we caught it quickly. The next one might not be so forgiving.

Follow Jayen

Jayen Ashar

Jayen Ashar

Founder and Technical Director, Scaleup Consulting