BigQuery storage pricing: active, long-term, logical and physical
BigQuery bills stored data per GiB-month at an active or long-term rate, measured in logical or physical bytes. How the 90-day rule works, what resets it, and what time travel adds to the bill.
BigQuery bills stored data in GiB-months, prorated per second, at one of two rates. Data in a table or partition that nobody has modified for 90 days moves to the long-term rate, and everything else is active. On top of that, each dataset picks how bytes are counted: logical (the uncompressed size, the default) or physical (the compressed size on disk). The first 10 GiB each month is free.
Storage is billed the same way whether your queries run on-demand or on capacity pricing.
The rates
Prices as of October 2026, in us-central1. Google lists them per GiB-hour, and the monthly figures below use a 730-hour month. Other locations, including the US multi-region, have different rates, so check yours on the pricing page.
| Billing model | Active, per GiB-month | Long-term, per GiB-month |
|---|---|---|
| Logical | $0.023 | $0.016 |
| Physical | $0.040 | $0.020 |
A full month of 1 TiB of active logical storage in us-central1 costs $23.55. Half a month of 100 GiB costs $1.15.
Google’s pricing page says the long-term price drops “by approximately 50%”. That holds for the physical rates above and not for the logical ones, where us-central1 shows about 30% off. Read the rates for your region rather than assuming a discount.
How big is a table? BigQuery counts bytes per column from the data types: 8 bytes for an INT64, 2 bytes plus the length for a STRING, and so on. The same sizes are used for query billing.
Active and long-term storage
If a table isn’t modified for 90 consecutive days, its storage is billed at the long-term rate. A partitioned table is judged one partition at a time, so last year’s partitions turn long-term while this month’s stay active. Nothing else changes: long-term data has the same speed, durability and availability.
WITH tables AS ( SELECT 'orders_2026_10' AS table_name, 500 AS logical_gib, 3 AS days_since_modified UNION ALL SELECT 'orders_2025', 2000, 400 UNION ALL SELECT 'orders_2026_07', 800, 91 UNION ALL SELECT 'orders_2026_08', 800, 89 ) SELECT table_name, IF(days_since_modified >= 90, 'long-term', 'active') AS tier, ROUND(logical_gib * IF(days_since_modified >= 90, NUMERIC '0.016', NUMERIC '0.023'), 2) AS usd_per_month FROM tables ORDER BY table_name
| table_name | tier | usd_per_month | |
|---|---|---|---|
| 1 | orders_2025 | long-term | 32 |
| 2 | orders_2026_07 | long-term | 12.8 |
| 3 | orders_2026_08 | active | 18.4 |
| 4 | orders_2026_10 | active | 11.5 |
orders_2025 was last modified 400 days ago, so its 2,000 GiB costs $32 a month. orders_2026_08 is the same size as orders_2026_07 but was modified 89 days ago instead of 91, so it still costs $18.40 instead of $12.80.
What resets the 90 days
Any change to the data puts the table, or the changed partition, back to active, and the 90-day timer starts again. Google’s pricing page lists these:
- A load job or query job that appends to or overwrites the table
- A copy job into the table
- Writing query results to the table
- DML (
INSERT,UPDATE,DELETE,MERGE,TRUNCATE) CREATE OR REPLACE TABLE- Streaming data into the table
These do not reset it: querying the table, creating a view over it, exporting from it, copying it to another table, and patching or updating the table resource.
Google’s cost guide disagrees on that last point. It says schema changes with ALTER, and changes to the description, labels or expiration, can also move data back to active storage. The two pages contradict each other, so don’t rely on metadata edits being free for old tables. Long-term pricing also only applies to data stored in BigQuery, not to external tables over Cloud Storage or Bigtable.
A common cause of a storage bill that goes up for no reason is a job that rewrites a whole old table, for example a nightly CREATE OR REPLACE TABLE that loads the same history again. Every partition restarts at active.
Logical or physical bytes
You set the billing model on each dataset. New datasets are logical. Your data is stored compressed either way, and the setting only changes what BigQuery measures and what it charges per GiB. Query speed doesn’t change.
Physical costs more per GiB, as the table above shows, so it only wins when your data compresses well. For active data, physical is cheaper when the logical size is more than about 1.7 times the physical size ($0.040 divided by $0.023). It also changes what else you pay for, which is the next section.
Time travel and fail-safe
When you change or delete data, BigQuery keeps the old version. For the time travel window (7 days by default, from 2 to 7 days) you can query the table as it was. After that, a fail-safe period of 7 more days lets Google Cloud support recover deleted data. You can’t read fail-safe data or change its length.
Whether you pay for those old bytes depends on the billing model:
| Logical | Physical | |
|---|---|---|
| Active and long-term bytes | Billed | Billed |
| Time travel bytes | Included in the logical rate | Billed at the active physical rate |
| Fail-safe bytes | Included in the logical rate | Billed at the active physical rate |
A table that was just created has no time travel or fail-safe cost. The cost appears when data is changed or deleted. In the physical model, a table that is overwritten or truncated often keeps up to 14 days of old versions on the bill. Google advises loading with append or MERGE instead of replacing tables, and shortening the time travel window if you don’t need seven days.
Deleting a table in a physical dataset can make the bill go up for a while. The deleted data stays billed at the active physical rate through time travel and fail-safe, and if it had been long-term data, it moves to active when it is deleted. Active physical bytes cost twice as much as long-term physical bytes.
This example compares two datasets that hold 1,000 GiB of logical data. events compresses to 250 GiB and rarely changes, so it carries only 25 GiB each of time travel and fail-safe data. orders compresses to only 600 GiB and is rewritten often, so it carries 100 GiB each of time travel and fail-safe data:
WITH datasets AS ( SELECT 'events' AS dataset, 1000 AS logical_gib, 250 AS physical_gib, 25 AS time_travel_gib, 25 AS fail_safe_gib UNION ALL SELECT 'orders', 1000, 600, 100, 100 ) SELECT dataset, ROUND(logical_gib * NUMERIC '0.023', 2) AS logical_usd, ROUND((physical_gib + time_travel_gib + fail_safe_gib) * NUMERIC '0.04', 2) AS physical_usd FROM datasets ORDER BY dataset
| dataset | logical_usd | physical_usd | |
|---|---|---|---|
| 1 | events | 23 | 12 |
| 2 | orders | 23 | 32 |
Physical billing makes events about half the price and orders more expensive. The figures use us-central1 active rates for everything and ignore long-term data.
Switching a dataset
ALTER SCHEMA my_dataset
SET OPTIONS (
storage_billing_model = 'PHYSICAL',
max_time_travel_hours = 48
);
This statement is not run on this page. It passes a dry run. Some rules apply:
- The change takes 24 hours to take effect.
- After a change you must wait 14 days before changing again.
- Tables in long-term storage stay long-term when you switch.
max_time_travel_hoursis a multiple of 24 from 48 to 168. The default is 168.- You can’t enroll a dataset in physical billing if your organization has legacy flat-rate slot commitments in the same region. Commitments bought with an edition don’t count.
- The
storage_billing_modeloption is only available on datasets last updated after December 1, 2022. Older untouched datasets are logical.
Forecast both models for your data
INFORMATION_SCHEMA.TABLE_STORAGE_BY_PROJECT has the sizes in both models. This query prices each dataset under each model. The DECLARE lines hold the us-central1 rates from above:
DECLARE active_logical_gib_price FLOAT64 DEFAULT 0.023;
DECLARE long_term_logical_gib_price FLOAT64 DEFAULT 0.016;
DECLARE active_physical_gib_price FLOAT64 DEFAULT 0.04;
DECLARE long_term_physical_gib_price FLOAT64 DEFAULT 0.02;
SELECT
table_schema AS dataset,
ROUND(
SUM(active_logical_bytes) / POW(1024, 3) * active_logical_gib_price
+ SUM(long_term_logical_bytes) / POW(1024, 3) * long_term_logical_gib_price, 2) AS logical_usd_per_month,
ROUND(
SUM(active_physical_bytes + fail_safe_physical_bytes) / POW(1024, 3) * active_physical_gib_price
+ SUM(long_term_physical_bytes) / POW(1024, 3) * long_term_physical_gib_price, 2) AS physical_usd_per_month
FROM `region-us`.INFORMATION_SCHEMA.TABLE_STORAGE_BY_PROJECT
WHERE table_type = 'BASE TABLE'
AND NOT deleted
GROUP BY dataset
ORDER BY logical_usd_per_month DESC;
This follows Google’s own forecast example and is not run here. In the physical column, active_physical_bytes already includes time travel bytes, so adding fail_safe_physical_bytes covers both. The numbers are a snapshot, and your bill is the bytes multiplied by how long you held them. For accurate figures use TABLE_STORAGE_USAGE_TIMELINE, which records usage over time.
In Querylab.io, a dataset’s Storage tab prices its storage under both models and shows what switching would save, and its “If switched to” block opens the ALTER SCHEMA statement in a new tab. A table’s Storage tab splits its bytes into active, long-term, time travel and fail-safe (Storage statistics).
Other things that are or aren’t billed
- Query results cache. Cached results are stored in temporary tables and are not billed. See Query cache.
- Temporary tables. Session and multi-statement-query temporary tables are billed as active storage only, and not for fail-safe.
- Snapshots and clones. You pay only for the data that differs from the base table.
TABLE_STORAGEshows them at full size, which overstates the cost. - Loading. Batch loading is free, using the shared slot pool. Streaming through the Storage Write API is billed separately. Google lists $0.025 per GiB, with the first 2 TiB each month free, for its gRPC form in us-central1.
- Expiration. Setting a table or partition expiration deletes data automatically. See Table expiration.
Comparing with the bill
The numbers in INFORMATION_SCHEMA won’t match an invoice exactly. The views use UTC, while the billing report’s days start at midnight Pacific time. The views don’t include taxes, adjustments or rounding. And a snapshot of bytes is not GiB-months: 31 GiB held for one day of a 31-day month is about 1 GiB-month.