# How to Avoid Overbilling in Firebase on the Blaze Plan

- Tool: Firebase
- Difficulty: Beginner
- Time required: 15-20 min
- Compatibility: Firebase Blaze plan, Google Cloud Console
- Last updated: March 2026

## TL;DR

Firebase Blaze plan has no hard spending cap, so overbilling prevention is entirely your responsibility. Set up budget alerts in Google Cloud Console to get notifications at spending thresholds. Prevent infinite Cloud Function loops with guard fields, optimize Firestore reads with pagination and caching, and monitor usage in the Firebase Console daily. Budget alerts only send notifications — they do not stop charges. For critical protection, consider programmatic billing controls that disable services when budgets are exceeded.

## Preventing Unexpected Firebase Bills on the Blaze Plan

Firebase's Blaze plan charges for usage beyond the free tier with no hard spending cap. Real incidents include bills of $70,000 in a single day from runaway Cloud Functions. This tutorial covers the essential safeguards: budget alerts, function loop prevention, Firestore cost optimization, usage monitoring, and programmatic controls. Every Firebase project on Blaze should implement these protections before going to production.

## Before you start

- A Firebase project on the Blaze (pay-as-you-go) plan
- Access to the Google Cloud Console (linked to your Firebase project)
- Basic understanding of Firestore pricing (per-read, per-write, per-delete)
- Firebase CLI installed for deploying function safeguards

## Step-by-step guide

### 1. Set up budget alerts in Google Cloud Console

Go to the Google Cloud Console at console.cloud.google.com and navigate to Billing > Budgets & alerts. Click Create budget, select your Firebase project, and set a monthly budget amount. Add alert thresholds at 50%, 80%, and 100% of your budget. Configure email notifications to go to your team's billing email. Remember: these alerts only send notifications. They do not cap or stop usage.

```
// Navigate to: console.cloud.google.com > Billing > Budgets & alerts
// Click: Create budget
// Settings:
//   Budget name: Firebase Production
//   Projects: your-firebase-project
//   Budget amount: $50 (or your expected monthly spend)
//   Alert thresholds: 50%, 80%, 100%, 150%
//   Notifications: your-team@company.com
```

**Expected result:** You receive email alerts when your Firebase project reaches each spending threshold.

### 2. Prevent infinite Cloud Function loops

The most common cause of massive Firebase bills is a Cloud Function that writes to the same Firestore collection it triggers on, creating an infinite loop. A single function bug can generate thousands of dollars in charges within minutes. Always add a guard field to prevent re-triggering, and check it at the top of every Firestore trigger handler.

```
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { logger } from "firebase-functions";

// DANGEROUS — this creates an infinite loop:
// export const bad = onDocumentCreated("orders/{id}", async (event) => {
//   await event.data.ref.update({ processed: true }); // triggers itself!
// });

// SAFE — guard field prevents re-triggering:
export const processOrder = onDocumentCreated(
  "orders/{orderId}",
  async (event) => {
    if (!event.data) return;
    const data = event.data.data();

    // Guard: skip if already processed
    if (data.processedByFunction === true) {
      return;
    }

    await event.data.ref.update({
      processedByFunction: true,
      totalWithTax: data.subtotal * 1.1,
    });

    logger.info(`Processed order ${event.params.orderId}`);
  }
);
```

**Expected result:** Cloud Functions include guard fields that prevent infinite re-triggering and runaway billing.

### 3. Optimize Firestore reads to reduce costs

Firestore charges per document read ($0.06 per 100,000 reads). The most common cost drivers are: reading entire collections instead of paginating, not using caching, and real-time listeners on large collections. Implement pagination with limit(), use aggregate queries for counts, and cache frequently accessed data.

```
import { db } from "@/lib/firebase";
import {
  collection, query, orderBy, limit, startAfter,
  getCountFromServer, getDocs
} from "firebase/firestore";

// BAD: Reading all documents (could be thousands of reads)
// const allDocs = await getDocs(collection(db, "products"));

// GOOD: Paginate with limit
async function getProducts(pageSize = 25, lastDoc?: any) {
  let q = query(
    collection(db, "products"),
    orderBy("createdAt", "desc"),
    limit(pageSize)
  );

  if (lastDoc) {
    q = query(q, startAfter(lastDoc));
  }

  return getDocs(q);
}

// GOOD: Use aggregate queries instead of reading all docs to count
async function getProductCount() {
  const snapshot = await getCountFromServer(
    collection(db, "products")
  );
  return snapshot.data().count; // 1 read instead of N reads
}
```

**Expected result:** Firestore reads are minimized through pagination and aggregate queries, reducing costs significantly.

### 4. Set minInstances wisely to control Cloud Functions costs

The minInstances option keeps function instances warm to eliminate cold starts, but each warm instance costs approximately $3-8 per month. Only set minInstances for user-facing HTTP functions where cold start latency matters. Event-driven triggers (Firestore, Auth) can tolerate cold starts since users do not wait for them directly.

```
import { onRequest } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";

// User-facing API — worth keeping warm
export const api = onRequest(
  {
    minInstances: 1,  // ~$3-8/mo, eliminates cold starts
    maxInstances: 10, // Cap maximum concurrent instances
  },
  async (req, res) => {
    res.json({ status: "ok" });
  }
);

// Background trigger — cold start is acceptable
export const onOrder = onDocumentCreated(
  {
    document: "orders/{orderId}",
    // No minInstances — saves money
    maxInstances: 5, // Still cap max to prevent runaway scaling
  },
  async (event) => {
    // process order
  }
);
```

**Expected result:** Functions have appropriate minInstances and maxInstances settings that balance cost with performance.

### 5. Monitor usage in the Firebase Console daily

Check the Firebase Console Usage & billing section regularly. The Usage tab shows Firestore reads/writes/deletes, Cloud Functions invocations, Storage bandwidth, and Hosting bandwidth. Look for unexpected spikes that indicate bugs or abuse. Set a calendar reminder to check usage daily during the first month after launching.

```
// Navigate to: Firebase Console > your project > Usage & billing
// Key metrics to monitor:
//   Firestore: reads/day, writes/day, storage
//   Cloud Functions: invocations/day, compute time
//   Storage: bandwidth, stored data
//   Hosting: bandwidth

// For programmatic monitoring, use the Cloud Monitoring API:
// console.cloud.google.com > Monitoring > Dashboards
```

**Expected result:** You have a routine for checking Firebase usage and can spot billing anomalies before they become expensive.

### 6. Set up programmatic billing safeguards

For additional protection, create a Cloud Function triggered by budget alert Pub/Sub notifications that automatically disables billing or scales down services when a budget threshold is exceeded. Google Cloud publishes a reference architecture for this. The function receives a Pub/Sub message when a budget alert fires and can take automated action.

```
import { onMessagePublished } from "firebase-functions/v2/pubsub";
import { logger } from "firebase-functions";

// This function is triggered by Cloud Billing budget alerts
// Set up: Billing > Budgets > Connect Pub/Sub topic
export const budgetAlert = onMessagePublished(
  "firebase-budget-alerts",
  async (event) => {
    const data = event.data.message.json;
    const budgetAmount = data.budgetAmount;
    const currentSpend = data.costAmount;
    const percentUsed = (currentSpend / budgetAmount) * 100;

    logger.warn(
      `Budget alert: ${percentUsed.toFixed(1)}% used ($${currentSpend}/$${budgetAmount})`
    );

    if (percentUsed > 120) {
      // Critical: Take emergency action
      // Option 1: Disable billing (requires Cloud Billing API)
      // Option 2: Set all function maxInstances to 0
      // Option 3: Alert on-call engineer via PagerDuty/Slack
      logger.error("CRITICAL: Budget exceeded 120%. Taking action.");
    }
  }
);
```

**Expected result:** A Cloud Function automatically responds to budget alerts and can take protective action when spending exceeds thresholds.

## Complete code example

File: `functions/src/billing-safeguards.ts`

```typescript
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { onMessagePublished } from "firebase-functions/v2/pubsub";
import { logger } from "firebase-functions";
import * as admin from "firebase-admin";

admin.initializeApp();

// Safe Firestore trigger with guard field to prevent infinite loops
export const processOrder = onDocumentCreated(
  {
    document: "orders/{orderId}",
    maxInstances: 5, // Cap scaling
  },
  async (event) => {
    if (!event.data) return;
    const data = event.data.data();

    // Guard: prevent infinite loop
    if (data.processedByFunction === true) return;

    await event.data.ref.update({
      processedByFunction: true,
      totalWithTax: data.subtotal * 1.1,
      processedAt: admin.firestore.FieldValue.serverTimestamp(),
    });

    logger.info(`Order ${event.params.orderId} processed`);
  }
);

// Budget alert handler — triggered by Pub/Sub from Cloud Billing
export const budgetAlert = onMessagePublished(
  {
    topic: "firebase-budget-alerts",
    maxInstances: 1,
  },
  async (event) => {
    const data = event.data.message.json;
    const percentUsed =
      (data.costAmount / data.budgetAmount) * 100;

    logger.warn(
      `Budget: ${percentUsed.toFixed(1)}% ($${data.costAmount}/$${data.budgetAmount})`
    );

    // Log to Firestore for dashboard visibility
    await admin.firestore().collection("billingAlerts").add({
      percentUsed,
      costAmount: data.costAmount,
      budgetAmount: data.budgetAmount,
      alertTime: admin.firestore.FieldValue.serverTimestamp(),
    });

    if (percentUsed > 150) {
      logger.error("CRITICAL: Budget exceeded 150%");
      // Implement your emergency action here
    }
  }
);
```

## Common mistakes

- **Assuming Firebase budget alerts will automatically stop charges when the budget is exceeded** — undefined Fix: Budget alerts are notification-only. They send emails and Pub/Sub messages but do NOT cap spending. You must implement programmatic safeguards or manually monitor usage to prevent overages.
- **Not setting maxInstances on Cloud Functions, allowing unlimited scaling during traffic spikes or bugs** — undefined Fix: Always set maxInstances on every function. A function without limits can scale to hundreds of instances during a bug or DDoS, generating massive charges.
- **Writing Firestore triggers that modify the same collection they listen to, creating infinite loops** — undefined Fix: Add a guard field (like processedByFunction: true) and check it at the top of every trigger. Return early if already processed.
- **Reading entire Firestore collections with getDocs(collection(db, 'items')) instead of paginating** — undefined Fix: Always use limit() to paginate queries. Use getCountFromServer() for counts instead of reading all documents just to count them.

## Best practices

- Set up Google Cloud budget alerts at 50%, 80%, 100%, and 150% thresholds before going to production
- Add guard fields to every Firestore trigger to prevent infinite loops — test in the emulator first
- Set maxInstances on every Cloud Function to cap scaling and prevent runaway charges
- Use pagination (limit + startAfter) for all Firestore queries instead of reading entire collections
- Use getCountFromServer() for counts instead of reading all documents and counting client-side
- Monitor Firebase Usage & billing weekly (daily during launches) to catch anomalies early
- Consider programmatic billing controls via Pub/Sub budget alerts for production projects
- Keep Firestore document sizes small and denormalize data to reduce the number of reads per page view

## Frequently asked questions

### Can I set a hard spending cap on the Firebase Blaze plan?

No. Firebase's FAQ explicitly states: 'No, you cannot cap your usage on the Blaze pricing plan.' Budget alerts are notification-only. For hard limits, you must implement programmatic controls that disable services when budgets are exceeded.

### What is the most common cause of unexpected Firebase bills?

Infinite Cloud Function loops — a function that writes to the same Firestore collection it triggers on. This can generate hundreds of thousands of function invocations and Firestore writes within minutes, causing bills of $10,000 or more.

### Does the Blaze plan free tier really give me free usage?

Yes. The Blaze plan includes the same free quotas as Spark: 50,000 Firestore reads/day, 20,000 writes/day, 2 million Cloud Functions invocations/month, and more. You only pay for usage above these limits.

### How quickly do budget alerts notify me?

Budget alerts can take several hours to process. Google Cloud updates cost data periodically, not in real-time. A fast-moving incident (like an infinite loop) can accumulate significant charges before the first alert arrives.

### Should I downgrade to Spark to avoid billing risk?

Spark eliminates billing risk since exceeding quotas simply shuts off the service. However, you lose Cloud Functions, phone authentication, and multiple database instances. If you need these features, stay on Blaze with proper safeguards.

### How do I check current Firebase usage?

Go to Firebase Console > your project > Usage & billing. This shows daily reads, writes, function invocations, and storage. For detailed cost breakdowns, use Google Cloud Console > Billing > Reports.

### Can Firebase App Check help reduce costs from abuse?

Yes. App Check verifies that requests come from your legitimate app, blocking automated bots and scrapers. This prevents unauthorized usage that could drive up Firestore reads and function invocations.

---

Source: https://www.rapidevelopers.com/firebase-tutorial/how-to-avoid-overbilling-in-firebase
© RapidDev — https://www.rapidevelopers.com/firebase-tutorial/how-to-avoid-overbilling-in-firebase
