Your Firebase project is fully broken: Firestore reads fail with 8 RESOURCE_EXHAUSTED: Quota exceeded, Functions return 503, Hosting serves quota errors — and you didn’t touch any code. The console banner reads Quota exceeded for quota metric .... This is almost always one of two things: a Spark (free) plan metric that hit its daily hard cap, or a runaway loop chewing through your allowance.
Fastest fix: open Firebase Console → Usage and billing and find the one metric sitting at 100%. If it’s Firestore reads/writes, the daily quota resets around midnight US Pacific time — so service self-heals overnight unless the runaway is still running. If you can’t wait, upgrade to Blaze (pay-as-you-go) and set a budget alert in the same session (Step 2 below). But do not stop there: find what burned the quota, or it refills and overflows again tomorrow.
Mental model: Firebase isn’t one quota. It’s dozens of independently metered metrics — Firestore reads / writes / deletes / stored GB, Functions invocations / GB-seconds, Hosting data transfer, Cloud Storage operations, phone-auth verifications. Any single one hitting its cap takes down whatever depends on it.
What changed in 2026 (read this first)
Two plan changes break older Firebase tutorials. Verify against your project before you debug:
- Cloud Functions now require the Blaze plan. You cannot deploy or run Cloud Functions on Spark anymore. If you have working Functions, you are already on Blaze — which means you do not have a hard cap; you have a runaway burning real money. (The old “125K invocations/month free on Spark” number is gone; the Blaze free allowance is 2M invocations/month, then billed.)
- Cloud Storage was removed from Spark, effective Feb 3, 2026. Spark projects lose access to default buckets and Storage API calls return
402/403. If your storage broke, it’s not a quota — it’s the plan change. You need Blaze to use Cloud Storage at all.
So before anything: confirm whether you’re on Spark (hard daily caps, can’t overspend) or Blaze (free allowance then billed, can overspend). Console → top-left gear / Usage and billing → Details & settings shows your plan.
Free-tier limits (as of June 2026)
These are the lines you can hit. Spark caps are hard (service shuts off, can’t overspend); Blaze gives the same allowance free, then bills you.
| Metric | Free allowance | Plan |
|---|---|---|
| Firestore reads | 50K / day | Spark + Blaze |
| Firestore writes | 20K / day | Spark + Blaze |
| Firestore deletes | 20K / day | Spark + Blaze |
| Firestore stored data | 1 GiB total | Spark + Blaze |
| Hosting stored data | 10 GB | Spark + Blaze |
| Hosting data transfer | 360 MB / day | Spark + Blaze |
| Functions invocations | 2M / month | Blaze only |
| Functions GB-seconds | 400K / month | Blaze only |
| Cloud Storage stored | 5 GB | Blaze only |
| Cloud Storage downloads | 1 GB / day | Blaze only |
| Phone auth verifications | varies by region, small daily cap | Spark + Blaze |
Note: the old Hosting “10 GB/month bandwidth” line is no longer how it’s billed — Hosting free transfer is now 360 MB/day (roughly 10.5 GB across a 30-day month, but it’s a daily gate, so one viral day trips it even if your month is light).
Which bucket are you in?
| Symptom | Most likely cause | Jump to |
|---|---|---|
| Reads at 100%, user count normal | Client listener loop or missing limit() | Causes 3, 7 / Steps 5, 7 |
| Reads spiked 100x, users flat | Open security rules + scraper/attacker | Cause 6 / Step 3 |
| Functions invocations in the millions | Function self-trigger loop | Cause 2 / Step 4 |
| Hosting transfer huge vs. traffic | Large file / video served from Hosting | Cause 4 / Prevention |
Storage 402/403, was working before | Cloud Storage left Spark (Feb 2026) | Upgrade to Blaze |
| Stored data over 1 GiB, few users | No TTL, logs/sessions piling up | Cause 5 |
Common causes
Ordered by hit rate, highest first.
1. Spark plan hit a daily hard cap
Spark is a hard ceiling — you cannot overspend, the metric just stops at the line. Firestore reads (50K/day) is the most common one. Service comes back at the next daily reset (midnight Pacific) if the thing draining it has stopped.
How to spot it: Console → Usage and billing → the metric at 100%. Error in client logs: 8 RESOURCE_EXHAUSTED: Quota exceeded.
2. Function loop burning invocations
Classic anti-pattern — a Firestore write trigger that writes back to the same collection:
// Write to Firestore triggers onWrite → which writes Firestore → ...
exports.onUserUpdate = onDocumentWritten('users/{uid}', async (event) => {
await db.doc(`users/${event.params.uid}`).update({...}); // triggers itself
});
On Blaze (where Functions live now) this can burn through the 2M free invocations in hours and then bill you for the rest of the month.
How to spot it: Console → Functions → a single function with absurd invocation counts (millions). Also visible in Cloud Logging.
3. Client loop reading Firestore
function Comp() {
useEffect(() => {
onSnapshot(query, snap => {
setItems(snap.docs); // re-render → useEffect runs again → subscribe again
});
}); // missing deps array
}
A handful of active users can drain 50K reads in under an hour.
How to spot it: Console → Firestore → Usage → reads/sec abnormally high relative to active users.
4. Large files / video blow Hosting data transfer
A 100 MB video on Firebase Hosting served to a few hundred viewers blows past the 360 MB/day free transfer in minutes.
How to spot it: Hosting data transfer huge relative to your actual traffic.
5. No Firestore TTL — old data piles up
Logs / sessions / analytics written to Firestore without cleanup eventually fill the 1 GiB stored-data cap.
How to spot it: Stored data over 1 GiB while real user-data volume is small.
6. Scraper / attacker hitting your data
Loose Firestore security rules let anyone with your client config query any collection directly. A scraper finds the endpoint and reads/writes explode.
How to spot it: User count flat, but reads spike 100x. Check Firestore Usage graph for a step change with no product launch behind it.
Shortest path to fix
Step 1: Identify which quota tripped
Firebase Console → Usage and billing
→ review Firestore / Functions / Hosting / Storage / Auth metrics
→ the one at 100% (or, on Blaze, the one whose graph hockey-sticked) is your culprit
Read the dashboard. Don’t guess.
Step 2: Emergency relief — Blaze + a budget alert
If you need service back now (Spark won’t refill until midnight Pacific), upgrade to Blaze and set a budget alert in the same session:
1. Google Cloud Console → Billing → Budgets & alerts → Create budget
2. Budget amount: the max monthly spend you'll tolerate (e.g. $20)
3. Alert thresholds: 50%, 90%, 100%
4. Alert recipients: your email
5. Optional hard stop: wire the Pub/Sub budget notification to a Cloud Function
that calls projects.updateBillingInfo to disable billing
Reality check: a budget alert does not cap spend — it only emails you. The only true hard stop is the Pub/Sub-triggered “disable billing” automation, and even that bills for charges already incurred before it fires. (Google’s own capping guide walks through the Cloud Function.) For a hard ceiling with zero overspend risk, stay on Spark and fix the runaway instead.
Step 3: Locate and stop the runaway
Source = client loop / Function loop / attacker
Function loop:
Console → Functions → find the one with insane invocations → Disable it
(or delete the deployment, then redeploy a fixed version)
Client loop:
Roll back the latest frontend deploy
Or hotfix the useEffect (add a deps array — Step 5)
Attacker / open rules:
Lock everything down immediately, then re-open only what you need:
// Emergency lockdown — paste, deploy, breathe, then re-open selectively
match /{document=**} { allow read, write: if false; }
Deploy with firebase deploy --only firestore:rules.
Step 4: Guard Functions against self-triggering
exports.onUserUpdate = onDocumentWritten('users/{uid}', async (event) => {
// If our own _serverUpdate flag is already set, this write came from us — bail.
const after = event.data?.after.data();
if (after?._serverUpdate) return;
await db.doc(`users/${event.params.uid}`).update({
derived: ...,
_serverUpdate: true, // mark so the next trigger short-circuits
});
});
Cleaner still: split source and derived data into two collections so the write path can’t feed back into the trigger.
Step 5: Fix the client useEffect deps
useEffect(() => {
const unsub = onSnapshot(query, snap => setItems(snap.docs));
return () => unsub(); // clean up the listener on unmount
}, []); // empty deps: subscribe once, not on every render
Step 6: Tighten Firestore rules (least privilege)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid} {
allow read, write: if request.auth.uid == uid;
}
match /posts/{post} {
allow read: if true;
allow write: if request.auth != null
&& request.resource.data.authorId == request.auth.uid;
}
}
}
Deploy: firebase deploy --only firestore:rules. Test rules first in Console → Firestore → Rules → Rules Playground before deploying.
Step 7: Reduce unnecessary reads
// Slow: full fetch every time
const all = await getDocs(collection(db, 'posts'));
// Fast: paginate + cache
const first = await getDocs(query(
collection(db, 'posts'),
orderBy('createdAt', 'desc'),
limit(20)
));
// In React, use SWR or TanStack Query to cache and dedupe fetches
How to confirm it’s fixed
- Console → Usage and billing: the metric that was at 100% should stop climbing (or, on Blaze, the reads/sec graph should drop back to baseline within a few minutes).
- Functions tab: invocation rate back to a sane number, no single function spiking.
- Client: no more
8 RESOURCE_EXHAUSTEDin your logs; reads succeed. - On Spark, full service returns at the next midnight-Pacific reset — but only if the runaway is dead. If the metric refills and trips again the next day, you stopped the symptom, not the source: go back to Step 3.
Prevention
- Set Google Cloud budget alerts (50% / 90% / 100%) before launching, and wire the Pub/Sub “disable billing” automation if you’re on Blaze.
- Default-deny Firestore rules; open only the exact paths you need. Never ship
allow read, write: if true;. - A Function must never subscribe to a collection it also writes to. If it must, use a flag to break the loop (Step 4).
- Always give
useEffecta deps array; enforce it witheslint-plugin-react-hooks. - Always add
limit()to Firestore queries, even in development — an unboundedgetDocsover a growing collection is a slow-motion quota bomb. - Don’t serve large files or video from Firebase Hosting (
360 MB/dayfree transfer). Use R2 / S3 + a CDN. - Add Firestore TTL policies for logs / sessions / analytics so stored data self-cleans.
- Monitor reads/sec and writes/sec; alert on anomalous spikes.
- Estimate monthly cost before launch — e.g.
(daily reads × 30 ÷ 100000) × $0.06 + ...for Firestore reads — so you know what “normal” looks like.
FAQ
Why did Firebase break when I changed nothing? A free-tier metric hit its daily cap — usually Firestore reads (50K/day) — driven by a client listener loop, a Function loop, or a scraper exploiting open rules. The trigger built up over hours, then crossed the line all at once.
Will it fix itself? On Spark, daily Firestore quotas reset around midnight US Pacific time, so service returns overnight — but only if whatever drained the quota has stopped. If it’s still running, it just trips again the next day.
Spark or Blaze — which protects me from a surprise bill? Spark. It can’t overspend; metrics simply stop at the cap. Blaze gives the same free allowance but then bills with no hard cap unless you build the Pub/Sub “disable billing” automation yourself. A budget alert alone only emails you.
My Cloud Storage / Cloud Functions suddenly returns 402/403 or won’t deploy. Quota? No — both now require the Blaze plan. Cloud Storage left Spark on Feb 3, 2026, and Functions have required Blaze for a while. Upgrade the project to Blaze (and set a budget alert) to use them.
How do I find the exact function that’s looping? Console → Functions shows per-function invocation counts; sort by it. Cloud Logging filtered to that function’s name shows whether each run is re-triggering a write. Disable the function to stop the bleed before you fix the code.
Does browsing data in the Firebase Console count against my read quota? Yes — the Console reads Firestore to render documents, and that counts. Avoid hammering large collections in the Data tab while you’re already near the cap.
Related
- Firebase deploy permission denied
- Firebase Function not found
- Firestore composite index missing
- Rate limit issue
Tags: #Firebase #Debug #Troubleshooting