Restore

Put those tables back

A snapshot is taken after you approve and before the statement is forwarded, on a separate admin connection. Denied holds cost no snapshot. The statement runs only after the snapshot commits. If the snapshot fails, the statement does not run (TB004) unless you approve it again with an explicit no-snapshot acknowledgement.

tablebelt restore
$ tablebelt restore snap_0001
restoring  public.users from snap_0001
ok         public.users (48,218 rows)
note       writes after snapshot are gone

Restore needs a TTY confirmation unless you pass --yes. --dry-run prints the plan and stops. --direct connects with the admin DSN when the proxy is down.

What comes back

Snapshotted tables return to their contents and structure at snapshot time. Writes to those tables after the snapshot are lost. Other tables are untouched. Objects that were not snapshotted are listed, not restored. Views dropped by CASCADE are in that list.

Current stateWhat restore does
Table missingRecreate from the manifest: sequences, table, rows, constraints, indexes, foreign keys, triggers, policies, RLS, ACL, owner, comments, then setval.
Same columns and typesIn place: replace rows and re-add anything missing.
Columns missing, the rest matchIn place, then ALTER TABLE ADD COLUMN for each missing column and load rows. Column order can differ.
Incompatible shapeRefused unless --replace. Drop the current table with no CASCADE, then recreate. Dependents must be listed, or pass --cascade.
DDL only snapshotRe-apply RLS, policies, constraints and triggers. Rows stay.

In-place replacement runs in one transaction. It drops inbound foreign keys, disables user triggers, truncates, copies rows back, and re-adds the foreign keys. If a child row written after the snapshot points at a parent that is gone, the constraint is left NOT VALID and the command prints the name. Sequences are set to the max of the current value and the captured value.

Before changing a table that still exists, restore takes a safety snapshot labelled as a pre-restore of that snapshot. Skip it with --no-safety-snapshot. If the table is over the size limit, --yes is required to proceed without that safety copy.

Consistency

DROP DATABASE

DROP DATABASE is held. v1 cannot snapshot a whole database, so will_snapshot is false and the reason is drop_database. Approval needs an explicit no-snapshot acknowledgement: tablebelt approve hold_0007 --no-snapshot, or the dashboard checkbox. The prompt says to take a host backup first. tablebelt init writes a deny-drop-database rule enabled by default, so a fresh install denies it outright.

Whole-database snapshots, partitioned tables, and foreign tables are not in this version. A plan with will_snapshot: false and reason partitioned_table or foreign_table also needs the no-snapshot acknowledgement. too_large means the hold is over snapshots.max_bytes_per_hold (default 1 GiB).

Retention

Default retention is 14 days and 5 GiB. An hourly loop, and a check before each new snapshot, deletes snapshots older than the retention, then oldest first until under the byte cap. It does not delete a snapshot younger than 24 hours unless a new snapshot would otherwise fail. Pro and Team do not change this. Snapshots never leave your database.

prune
tablebelt snapshots prune --older-than 7d --keep 10