All posts
BigQueryGoogle CloudCost Control

How to Set BigQuery Quotas to Avoid Surprise Bills

Published 21 May 2026·11 min read
Peter Claridge
Founder, KeywordHistory · Fractional CMO at Riverforge

BigQuery quota and usage caps are not enabled by default. That's the thing that surprises most people who end up with a shock bill. You set up a project, connect some data, start running queries, and assume there's some built-in protection that kicks in before anything catastrophic happens. There isn't.

In February 2024, a user ran queries against the HTTP Archive public dataset using the official GCP Python library. The library, unlike the BigQuery web UI, doesn't show cost estimates before executing. The result: a $14,000 bill from processing 2.5 petabytes of data in a matter of hours. A separate incident involved a developer receiving a $5,000+ charge for a single BigQuery query.

The common thread in every one of these stories: the cost controls existed, were opt-in, and nobody had set them up.

This guide covers exactly how to implement BigQuery quota and usage caps across five layers, so that no single query, no matter how badly written, can produce a bill that keeps you up at night.

Understanding How BigQuery Charges You

BigQuery offers two pricing models. On-demand charges per byte scanned when a query runs. The current rate is $6.25 per TiB processed. The free tier covers the first 1 TiB of queries per month and 10 GiB of storage. Capacity-based (slot reservations) charges a flat rate for committed compute capacity, which makes more sense for teams running many queries per day.

A few cost mechanics that catch people off-guard:

  • LIMIT clauses do not reduce bytes scanned. Writing SELECT * FROM my_table LIMIT 100 does not mean BigQuery reads only 100 rows. It scans the entire table and returns 100 rows. You're billed for the full scan.
  • There is a minimum charge of 10 MiB per table per query, even if the table is tiny.
  • Long-term storage saves money automatically. Tables unmodified for 90 consecutive days automatically qualify for long-term storage pricing - roughly half the active storage rate.
BigQuery on-demand query cost at $6.25/TiB. Source: Google Cloud BigQuery Pricing.

Layer 1: Maximum Bytes Billed (Per-Query Hard Stop)

This is the most important control to set up immediately, especially if anyone on your team uses the Python client library or any programmatic interface. Maximum bytes billed is a per-query setting that causes a query to fail before it runs if the estimated bytes to be scanned exceeds your threshold. No scan happens. No charge is incurred. You get an error instead.

Setting it in the BigQuery Console

  1. Open BigQuery Studio
  2. Click the three-dot menu next to the query editor and select "Query Settings"
  3. Under Advanced Options, find "Maximum bytes billed"
  4. Enter your threshold in bytes (10 GB = 10,000,000,000)

Setting it in Python

from google.cloud import bigquery

client = bigquery.Client()

job_config = bigquery.QueryJobConfig(
    maximum_bytes_billed=10 * 1024**3  # 10 GB
)

query_job = client.query(query, job_config=job_config)
# Raises BadRequest if estimated bytes > 10 GB — no charge incurred

A reasonable threshold for GSC data analysis is 10-100 GB depending on your dataset size. This is generous enough to run any sensible query but will catch runaway SELECT * on multi-year datasets.

Layer 2: Custom Daily Quotas (Project and User Level)

Maximum bytes billed protects against a single bad query. Custom quotas protect against sustained overuse across many queries over a day. BigQuery has two types of custom quota, as documented in Google's quota configuration guide:

  • QueryUsagePerDay - limits total bytes processed across the entire project per calendar day (resets at midnight Pacific Time)
  • QueryUsagePerUserPerDay - limits bytes processed per individual user per day

Setting Custom Daily Quotas

  1. Open Google Cloud Console and navigate to IAM & Admin > Quotas & System Limits
  2. Filter by Service: "BigQuery API"
  3. Find "Query usage per day" and "Query usage per day per user"
  4. Select the quota, click "Edit", deselect "Unlimited", and enter your threshold in TiB
  5. Submit - lower quotas take effect within minutes
These quotas are approximate. BigQuery may occasionally allow queries that slightly exceed the threshold. Do not treat custom quotas as an absolute financial guarantee. Use them in combination with budget alerts and maximum bytes billed for defence in depth.
Control LayerScopeHard Stop?Best For
Maximum bytes billedPer queryYes - query fails before runningCatastrophic single queries
QueryUsagePerDayProject / dayApproximateTotal daily project spend
QueryUsagePerUserPerDayUser / dayApproximatePreventing one user consuming all quota
Budget alertsBilling account / monthNo - notification onlyVisibility and escalation
Table partitioningPer query (structural)Yes - reduces bytes scannedReducing baseline cost
Source: Google Cloud BigQuery Documentation

Layer 3: Budget Alerts

Budget alerts don't stop charges, but they give you visibility before things spiral. Combined with the controls above, they complete the safety picture.

  1. Open Google Cloud Console > Billing > Budgets & Alerts
  2. Click "Create Budget" and set the scope to your specific project
  3. Enter a budget amount and configure threshold rules (50%, 90%, and 100% of budget)
  4. Add email recipients for each threshold

For more advanced setups, you can connect budget alerts to a Pub/Sub topic and trigger automated remediation. For most teams, email alerts at multiple thresholds are sufficient when combined with maximum bytes billed and custom quotas.

Layer 4: Structural Cost Reduction with Partitioning

Partitioning reduces your baseline cost on every query, making the budget alerts and quotas less likely to trigger in the first place. The GSC BigQuery export tables are partitioned by data_date out of the box. Including a date filter means BigQuery only scans the relevant partitions. Without a date filter, it scans everything.

According to analysis from The SEO Community, adding proper partition filters to BigQuery-GSC queries can cut costs by 80% or more as datasets grow.

Relative query cost vs. date range filter on a 2-year GSC dataset. Source: The SEO Community.

The habit to build: every query against your GSC data should include a WHERE data_date BETWEEN x AND y or WHERE data_date >= DATE_SUB(CURRENT_DATE(), INTERVAL N DAY) clause. No exceptions.

Layer 5: Dry Runs and Query Cost Estimation

Before running an unfamiliar query against a large dataset, estimate the bytes it will scan first.

In the BigQuery Console

The query editor automatically estimates bytes when you write a query. You'll see something like "This query will process X MB when run" in the bottom right of the editor, before you click Run.

In the command line

bq query --dry_run --use_legacy_sql=false \
  'SELECT query, SUM(clicks) AS clicks
   FROM `project.dataset.searchdata_site_impression`
   WHERE data_date >= "2026-01-01"
   GROUP BY query'

In Python

job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)
query_job = client.query(query, job_config=job_config)
print(f"Estimated bytes: {query_job.total_bytes_processed:,}")

Monitoring Who's Spending What

The INFORMATION_SCHEMA.JOBS view shows which queries and users are driving the most cost, without any additional setup:

SELECT
  user_email,
  COUNT(*)                                                    AS query_count,
  SUM(total_bytes_processed) / POW(1024, 4)                  AS total_tib_processed,
  ROUND(SUM(total_bytes_processed) / POW(1024, 4) * 6.25, 2) AS estimated_cost_usd
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE
  creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND job_type = 'QUERY'
  AND state    = 'DONE'
GROUP BY user_email
ORDER BY total_tib_processed DESC;

The Recommended Setup for GSC Analytics Teams

If your team is primarily using BigQuery to analyse GSC data rather than running large-scale data warehouse workloads, this setup gives you solid protection:

  • Maximum bytes billed: Set to 50 GB per query
  • QueryUsagePerDay: Set to 0.2-0.5 TiB per day for the project
  • QueryUsagePerUserPerDay: Set to 0.1 TiB per user per day
  • Budget alert: Set to your expected monthly spend with alerts at 50% and 90%
  • Always include date filters on queries against GSC tables

Conclusion

BigQuery quota and usage caps exist to prevent the kind of billing disasters that make it onto Hacker News. The controls are comprehensive and effective. The only problem is that none of them are on by default. The five layers covered in this guide give you defence in depth:

  • Maximum bytes billed stops catastrophic single queries before they run
  • Custom daily quotas cap sustained overuse at the project and user level
  • Budget alerts give you visibility before charges compound
  • Table partitioning reduces baseline cost on every query
  • Dry runs let you estimate cost before committing to execution

Set these up before you run your first production query, not after. For teams analysing Google Search Console data specifically, Keyword History connects to your existing BigQuery dataset and runs cost-optimised queries automatically - so your team can access SEO insights without having to think about bytes billed.

Peter Claridge

Written by

Peter Claridge

Founder, KeywordHistory · Fractional CMO at Riverforge

Led organic growth at Unmetric, eG Innovations, and StreamAlive over 13+ years. Built KeywordHistory after rebuilding the same Google Data Studio dashboards one too many times.

Connect on LinkedIn

Keep your keyword history forever.

Every day you wait, Google deletes another day of your GSC data. KeywordHistory backs up to BigQuery automatically and surfaces the insights that matter.

Start free