Table snapshots and table clones in BigQuery
A BigQuery table snapshot is a read-only copy that you keep as long as you like. A table clone is a writable copy. Both are billed only for the data that differs from the base table. How to create them, what blocks you, and how to restore from one.
A table snapshot is a read-only copy of a table at one moment. A table clone is a writable copy. Neither copies the data when you create it: BigQuery shares the base table’s storage, and you pay only for bytes that later differ from the base table. Use a snapshot to keep a table as it was, for longer than the 7-day time travel window allows. Use a clone when you want to change the copy, for a test or a sandbox.
Create a snapshot
CREATE SNAPSHOT TABLE sales.orders_2026_10_06
CLONE sales.orders
OPTIONS (expiration_timestamp = TIMESTAMP '2027-01-01 00:00:00+00');
The keyword is CLONE for snapshots too. The source can be a table, a clone or another snapshot. You can query the snapshot like any table.
Add FOR SYSTEM_TIME AS OF to snapshot the table as it was earlier, inside its time travel window. This is also how you freeze a table’s state from before a bad change, before the window ends:
CREATE SNAPSHOT TABLE sales.orders_before_fix
CLONE sales.orders
FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 3 HOUR);
A snapshot never overwrites. If the name is taken, the statement fails with Already Exists, IF NOT EXISTS skips it, and OR REPLACE isn’t allowed at all:
CREATE OR REPLACE SNAPSHOT TABLE sales.orders_snapshot CLONE sales.orders
OR REPLACE is not allowed with CREATE SNAPSHOT TABLE. at [1:1]
To refresh a snapshot, drop it and create it again. A snapshot is dropped with its own statement. DROP TABLE on a snapshot fails with Cannot drop ... which has type SNAPSHOT. A table was expected.
DROP SNAPSHOT TABLE sales.orders_2026_10_06;
Create a clone
CREATE TABLE sales.orders_dev
CLONE sales.orders;
The clone takes the same options as CREATE TABLE, and FOR SYSTEM_TIME AS OF works here too. The result is a table you can query, insert into, update and drop with DROP TABLE. After creation it is independent: changes to the base table don’t show up in the clone, and the other way round.
In Querylab.io, a table’s SQL Templates include CLONE TABLE (DDL operations), and Bulk Generate writes a CREATE TABLE ... CLONE statement for every table in a dataset that matches a name pattern (Bulk operations).
We created a 3-row table, a snapshot and a clone of it, then deleted a row from the base and inserted one into the clone. The row counts:
| Table | Rows |
|---|---|
| base | 2 |
| snapshot | 3 |
| clone | 4 |
The snapshot kept what the table looked like when it was taken. The clone moved on by itself.
Snapshots are read-only
INSERT, UPDATE, DELETE and ALTER TABLE ... ADD COLUMN on a snapshot all fail:
Table myproject:mydataset.orders_snap is a snapshot, and snapshots are immutable.
ALTER TABLE does not support modifying the schema of a(n) SNAPSHOT: orders_snap
You can change a snapshot’s metadata: description, expiration and access policy.
Restore from a snapshot
A snapshot is restored by cloning it into a table:
CREATE TABLE sales.orders_restored
CLONE sales.orders_2026_10_06;
We ran this on a test snapshot and the new table had all 3 of the snapshot’s rows. To replace the broken table itself, drop it (inside its own time travel window you can still undo that, see Time travel) and create a clone under the old name.
How a snapshot or a clone shows up in metadata
INFORMATION_SCHEMA.TABLES has the type and the base table:
SELECT table_name, table_type, base_table_name, snapshot_time_ms
FROM sales.INFORMATION_SCHEMA.TABLES;
In our test this returned BASE TABLE, CLONE and SNAPSHOT for the three tables, with the base table’s name in base_table_name for the last two. snapshot_time_ms holds the moment the copy was taken, which is the time travel timestamp if you used one. The ddl column of a snapshot is a ready CREATE SNAPSHOT TABLE ... CLONE ... FOR SYSTEM_TIME AS OF statement, with the exact snapshot time in it.
What it costs
Creating either one costs nothing in storage at first. After that:
- A snapshot or clone has the same storage type as its source. A snapshot of long-term data is long-term.
- When you change or delete data in the base table that a snapshot also holds, the snapshot is charged for those bytes. If several snapshots hold the same changed data, only the oldest is charged.
- In a clone, the changes you make to the clone are charged to the clone. New data in the base table after the clone was made stays on the base table’s bill.
- With physical storage billing, the time travel and fail-safe charges for the base table are not applied while snapshots hold the data. They are charged when the snapshot is deleted.
- A copy job (
bq cp) of a snapshot or clone, to the same or to another region, is a full copy and is billed as a full table.
To see how many bytes a table, snapshot or clone holds, use INFORMATION_SCHEMA.TABLE_STORAGE. See Storage pricing.
Limits
- A snapshot or clone must be in the same region, and the same organization, as its base table. Cloning across projects is allowed. Cloning from an EU dataset into a US dataset is not. If you pick a dataset in another region for a snapshot, BigQuery makes a full copy there instead.
- You can’t snapshot or clone a view, a materialized view or an external table. For a view, BigQuery answers
Cannot snapshot ... which has type VIEW. Allowed types: [TABLE, SNAPSHOT], and the clone error is the same with “clone”. - Data in the streaming buffer (recently streamed rows) is not in the copy.
- The snapshot time can’t be older than the table’s time travel window. Google’s snapshot guide says 7 days.
- A partitioned table’s partition expiration is not kept by a snapshot. The snapshot uses the destination dataset’s default partition expiration. Google’s advice is to copy the table instead if you need to keep it.
- A clone can’t append to an existing table. To add data to a table, use a normal copy.
- A clone takes a variable time to create, because storage is managed dynamically.
Snapshot, clone or copy?
A snapshot is read-only, a clone is writable, and a copy (bq cp or CREATE TABLE AS SELECT) is a full, independent table that costs its whole size in storage from the start. Drop a snapshot with DROP SNAPSHOT TABLE, and a clone or copy with DROP TABLE. Use CREATE TABLE ... AS SELECT when the copy needs a different shape or a filter, because snapshots and clones always take the whole table.