# 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. Source: https://docs.querylab.io/bigquery/snapshots-and-clones/ Updated: 2026-10-14 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](https://docs.querylab.io/bigquery/time-travel/) window allows. Use a clone when you want to change the copy, for a test or a sandbox. ## Create a snapshot ```sql 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: ```sql 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 is refused** ```sql CREATE OR REPLACE SNAPSHOT TABLE sales.orders_snapshot CLONE sales.orders ``` BigQuery rejects this query: ```text 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.` ```sql DROP SNAPSHOT TABLE sales.orders_2026_10_06; ``` ## Create a clone ```sql 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](https://docs.querylab.io/schema-browser/ddl-operations/)), and Bulk table actions write a `CREATE TABLE ... CLONE` statement for every table in a dataset that matches a name pattern ([Bulk operations](https://docs.querylab.io/data-management/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: ```text 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: ```sql 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](https://docs.querylab.io/bigquery/time-travel/)) and create a clone under the old name. ## Snapshots and clones in metadata `INFORMATION_SCHEMA.TABLES` has the type and the base table: ```sql 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](https://docs.querylab.io/bigquery/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. Open the playground at https://app.querylab.io?playground=true&utm_source=docs&utm_medium=concepts to run it. It is the real app on public BigQuery datasets and needs no sign-in. ## Sources Based on the BigQuery documentation by Google, CC BY 4.0, rewritten with examples checked against BigQuery: - [Introduction to table snapshots](https://cloud.google.com/bigquery/docs/table-snapshots-intro) - [Introduction to table clones](https://cloud.google.com/bigquery/docs/table-clones-intro) - [CREATE SNAPSHOT TABLE and CREATE TABLE CLONE](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)