Ask
44

What actually burns Firestore's 50K reads/day on the free Spark plan, and how do I see it before the quota resets? Quota hit

Small app, a few hundred users, and I keep exhausting the Firestore read quota by mid afternoon.

The no-cost limits on the Firebase pricing page today are 50K document reads/day, 20K writes/day, 20K deletes/day, 1 GiB stored and 10 GiB/month egress, and the daily ones reset around midnight Pacific. Checked those this morning rather than quoting from memory, because I have found stale numbers in three different blog posts already.

The part I cannot explain is the ratio. Traffic is flat but reads are not. Some days 12K, some days over 50K, with no matching change in sessions. So it is something structural in the app rather than popularity.

Before I start rewriting queries at random:

  1. What are the usual causes of read counts far larger than the number of things a user actually looked at?
  2. Is there any way to attribute reads to a query or a screen, rather than staring at one daily total after the fact?
  3. Does anything other than user traffic count against it?
8 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @edge_runtime_bo · 2d ago · 2 replies

    Listeners, almost certainly.

    A snapshot listener bills for the documents it delivers, and it delivers the whole matching set when it attaches. So a screen that attaches a listener to a collection, and re-attaches on every navigation, tab focus, reconnect or hot reload, pays for that set again each time. One screen showing 200 documents, mounted a few hundred times across your users in a day, is your entire allowance on its own and there is no single dramatic event in your traffic graph to point at.

    What to look for: listeners that are never unsubscribed, listeners attached in a component that remounts, and anything that re-subscribes on network flap. That last one explains days that are 4x other days with identical traffic, because it depends on how good your users' connections were.

    27
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @oncall_omar · 20h ago

      And a dev tab left open overnight with a live listener attached will quietly consume a day's allowance while you sleep, which is the single most demoralising way to discover this. Check that before you conclude your users are doing something weird.

      11
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @ramen_profit_ray · yesterday

    Second big one: reading a collection in order to count it. If any screen shows "you have 47 of these", and it gets that number by pulling 47 documents, you are paying 47 reads for one integer that the user glances at.

    Two fixes, in order of effort. Use the count aggregation rather than fetching documents. Or, if the counter is on a screen everyone opens, denormalise it into a single document you update on write. Writes are 20K/day, and one write per change is much cheaper than N reads per view.

    This one is worth auditing specifically because it does not feel like a read-heavy operation while you are writing it.

    19
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @two_vcpu_club · yesterday

    Answering (3): your own development traffic counts. Same project, same daily quota. Every hot reload that re-runs a query, every time you open the console and browse a collection, every integration test run.

    Use the local emulator suite for day to day work, and a separate project for staging so it has its own quota. For a lot of small apps this alone is the difference between comfortably inside the limit and running out at 3pm, and it costs nothing to change.

    15
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @indent_error_ivy · 2h ago

    On (2): you will never get attribution from the daily total, so instrument the client.

    Wrap the read helpers in one function that takes a label. Increment a counter per label with the number of documents returned. Ship the counters somewhere once a session, or just log them in dev and look. Twenty minutes of work and it usually names the guilty screen on the first day, because these things are never evenly spread, it is always one query doing 80% of it.

    I resisted this for a week and did guesswork rewrites instead, all of which were wrong.

    12
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @costbasis_carl · 2h ago

    Worth saying out loud once: sometimes the answer is that the free tier is the wrong size for your app and the cheapest available fix is to stop engineering for zero.

    Do the instrumentation first, because a genuinely broken listener will follow you onto the paid plan and cost real money there. But if after that you are simply an app that legitimately needs more than 50K reads a day, weeks of your time to stay at $0 is not a good trade. Decide it deliberately rather than drifting into it.

    7
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @deficit_dot · 2d ago · 2 replies

    Are you sure you are reading the limit right? I was under the impression the 50K is per user per day, in which case a few hundred users would be nowhere near it and you would be looking for one abusive client rather than a structural problem.

    5
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @pgpolicy_nadia · yesterday

      It is per project per day, across all users, not per user. That is precisely why an app with a few hundred users can exhaust it.

      Do the arithmetic with the real number: one screen that reads 200 documents when it opens, opened five times a day by two hundred users, is 200,000 reads. Four times the daily allowance from a single screen and a plausible amount of usage. The per-user reading makes the free tier sound enormous and it is not, it is a shared bucket that one careless query can drain.

      This is worth correcting loudly because people design around the per-user version and then cannot understand their own numbers.

      22
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report