Per-query cost guard for cloud databases. Set dollar or byte limits before any query runs.
Project description
query-cost-guard
Per-query cost guard for BigQuery. Set dollar or byte limits before any query runs.
Why
BigQuery charges per byte scanned. A single bad query can burn through your daily quota.
The native maximum_bytes_billed only speaks in bytes — this package lets you think in dollars.
Install
pip install query-cost-guard
# With CLI
pip install query-cost-guard[cli]
Usage
Dollar-based guard
from google.cloud.bigquery import Client
from query_cost_guard import QueryCostGuard, QueryParams
guard = QueryCostGuard(client=Client())
result = guard.query(
sql="SELECT * FROM `project.dataset.table` WHERE date > '2026-01-01'",
params=QueryParams(max_cost_usd=0.50),
)
result.rows # list[dict]
result.actual_cost_usd # 0.03
result.bytes_billed # 4_831_838_208
result.duration_seconds # 2.41
Byte-based guard
result = guard.query(
sql="SELECT * FROM `project.dataset.table`",
params=QueryParams(max_bytes=5 * 1024**4), # 5 TiB
)
max_cost_usd and max_bytes are mutually exclusive.
When cost exceeds the limit
BigQuery rejects the query before execution — no bytes are billed.
from query_cost_guard import QueryCostExceededError, QueryParams
try:
result = guard.query(sql=huge_query, params=QueryParams(max_cost_usd=0.10))
except QueryCostExceededError as e:
e.context.estimated_cost_usd # 2.34
e.context.max_cost_usd # 0.10
e.context.bytes_estimated # 374_000_000_000
With existing job config
from google.cloud.bigquery import QueryJobConfig, ScalarQueryParameter
result = guard.query(
sql=sql,
params=QueryParams(max_cost_usd=1.00, query_tag="observation_troubleshooting"),
job_config=QueryJobConfig(
query_parameters=[ScalarQueryParameter("account_id", "INT64", 115)]
),
location="US",
)
Pricing
Live pricing is fetched from the Cloud Billing Catalog API and cached for 24 hours. If the API is unavailable, falls back to the static rate of $6.25/TiB.
from query_cost_guard import QueryCostGuard, OnPricingFailure
# Fail hard if pricing can't be resolved
guard = QueryCostGuard(client=client, on_pricing_failure=OnPricingFailure.RAISE)
# Or pin a known price
guard = QueryCostGuard(client=client, price_per_tib_override=6.25)
Dry-run estimation
estimate = guard.estimate(sql="SELECT * FROM `project.dataset.big_table`")
estimate.estimated_bytes # 4_831_838_208
estimate.estimated_cost_usd # 0.0275
estimate.price_per_tib_usd # 6.25
CLI
Estimate query cost without executing:
query-cost-guard --project my-gcp-project estimate \
--query "SELECT * FROM \`project.dataset.table\`"
# Estimated bytes: 4,831,838,208
# Estimated cost: $0.0275 (at $6.25/TiB)
With a cost threshold:
query-cost-guard --project my-gcp-project estimate \
--query "SELECT * FROM big_table" \
--max-cost 0.50
# Guard: ✓ PASS (limit $0.50)
JSON output, file input, stdin:
query-cost-guard --project my-proj estimate --query "SELECT 1" --json
query-cost-guard --project my-proj estimate --file query.sql
cat query.sql | query-cost-guard --project my-proj estimate
Credentials default to Application Default Credentials. Override with --credentials /path/to/sa.json.
How it works
Uses BigQuery's maximum_bytes_billed on the QueryJobConfig. Single API call, no race condition, enforced server-side.
Both estimate() and the CLI use dry_run=True for zero-cost estimation.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file query_cost_guard-0.1.2.tar.gz.
File metadata
- Download URL: query_cost_guard-0.1.2.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9bb4b4f8a6dd51e8cd41fceba9297c812672348e053473d330ea34eee4fad288
|
|
| MD5 |
104171eb2c1ee19cc28fd8ac5560fe17
|
|
| BLAKE2b-256 |
3dc0a4a8fca753cf96dd120acfc5fee55297d454697764a5631c02250340352f
|
Provenance
The following attestation bundles were made for query_cost_guard-0.1.2.tar.gz:
Publisher:
release.yml on yaelmi3/query-cost-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
query_cost_guard-0.1.2.tar.gz -
Subject digest:
9bb4b4f8a6dd51e8cd41fceba9297c812672348e053473d330ea34eee4fad288 - Sigstore transparency entry: 983329460
- Sigstore integration time:
-
Permalink:
yaelmi3/query-cost-guard@bdd08aaef4beb080d023b0af662922d92670caaf -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/yaelmi3
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdd08aaef4beb080d023b0af662922d92670caaf -
Trigger Event:
push
-
Statement type:
File details
Details for the file query_cost_guard-0.1.2-py3-none-any.whl.
File metadata
- Download URL: query_cost_guard-0.1.2-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
daefc31fb143532b763731b3a6643d1307f72523f053289ab450bfa5fc33831f
|
|
| MD5 |
4d5c024d40fff293e984860247a59ecc
|
|
| BLAKE2b-256 |
290ac0f56f5fa315f42c16237b4abf8f37e3a8f5789eab982cb840b431c3faec
|
Provenance
The following attestation bundles were made for query_cost_guard-0.1.2-py3-none-any.whl:
Publisher:
release.yml on yaelmi3/query-cost-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
query_cost_guard-0.1.2-py3-none-any.whl -
Subject digest:
daefc31fb143532b763731b3a6643d1307f72523f053289ab450bfa5fc33831f - Sigstore transparency entry: 983329469
- Sigstore integration time:
-
Permalink:
yaelmi3/query-cost-guard@bdd08aaef4beb080d023b0af662922d92670caaf -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/yaelmi3
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdd08aaef4beb080d023b0af662922d92670caaf -
Trigger Event:
push
-
Statement type: