On this page

Backups

Every project can be restored to any moment of the last 24 hours (Free) up to 30 days (Enterprise), in place or into a new branch. Paid projects also get a daily restore point.

LimitFreeProScaleEnterprise
Backup retentionNo backups7 days14 days30 days
Point-in-time recovery1 days7 days14 days30 days
Deleted rows kept in the recycle bin1 days7 days14 days30 days

#How your data is protected

  • Continuous change log. Every change to every database is streamed off your project's server as it happens, to a different machine, so even a lost server loses at most the last few seconds.
  • Daily restore points (paid plans). Once a day each project gets a restore point of its whole database (every schema: tables, auth users, storage file records, functions, policies and settings), kept from the server's encrypted snapshots and continuous change log. Restore points are kept daily for 7 days, then one per week up to your plan's retention.
  • Point-in-time recovery (every plan): restore the database to any second of the last 24 hours on Free, 7 days on Pro, 14 days on Scale and 30 days on Enterprise.

Backups are encrypted (AES-256) and kept for your plan's retention period; the newest restore point is always kept. Free projects have no daily backups: their Backups page has point-in-time recovery and lists the backups a restore takes (the state before it), kept for a day. To keep your own copies, export the data with pg_dump or stitchdb db dump (below).

#In the dashboard

Open your project and choose Backups (also in Studio under Database › Backups):

  • Back up now takes an extra backup (at most one per hour).
  • Export current data gives you a link, valid for 15 minutes, that downloads a fresh pg_dump file (custom format) of the database as it is now. Nothing is stored on our side.
  • Download next to a backup gives you that backup's database dump, and Files (when it includes them) the project's stored files. Large databases get restore points instead, with no file: to get an earlier day as a file, restore it (below) and then export; the state before the restore is kept, so you can restore back to it.
  • Restore… replaces the project database with the backup. A backup of the current state is taken first and listed as Before a restore, so a restore can itself be undone.
  • Restore to a point in time rewinds the database to the moment you pick. On plans with preview branches (Pro and up) you can choose Restore into: A new branch instead: a new branch gets the database as it was at that moment, with its own URL and keys, and the project itself is not changed. Use it to look at or copy back data without rewinding production. The branch counts toward your plan's branches and is listed under Branches; stored files are not copied into it.

#Restore one table

Restore one table… (next to Restore to this moment) brings back a single table as it was at a moment of your point-in-time window, without rewinding anything else. Use it after a bad update or delete, or to get back a dropped table. The table is loaded next to the live one, in the _stitch_restore schema as <table>_<date>_<time>, with its rows, columns and indexes (no foreign keys, triggers or policies). Then, as you choose:

  • Only restore the copy: the live table is not changed. Compare or copy rows yourself in the SQL editor, for example insert into public.orders select * from _stitch_restore.orders_20261025_134501 where id = 42.
  • Put old rows back (needs a primary key): deleted rows come back and changed rows get their old values; rows added since stay. You can limit it with a condition, for example customer_id = 42.
  • Replace all rows: the table gets exactly the rows of that moment. Its rows from before are kept in _stitch_restore.<table>_before_<date>.

Putting rows back runs in one transaction as your database owner, so your triggers and foreign keys apply and a failure changes nothing. Copies in _stitch_restore are removed after 7 days and count towards the database size until then.

#Recycle bin

Turn on the recycle bin for a table on the Backups page and every row deleted from it, by your app, an API call, the SQL editor or a cascade, is kept for your plan's retention (1 day on Free, 7 days on Pro, 14 on Scale, 30 on Enterprise). The page lists the latest deleted rows, who deleted them (the signed-in user's id, service_role / anon for API calls with those keys, or the database role) and when; tick some and choose Restore selected. A row whose primary key exists again is skipped. From SQL:

SQL
-- the latest deleted rows of a table
select id, deleted_at, deleted_by, "row" from _stitch_bin.rows
where tbl = 'public.orders'::regclass and restored_at is null order by id desc limit 20;
-- put rows back (returns how many)
select _stitch_bin.restore(array[41, 42]);

Emptying a table with truncate and dropping it are not kept (use Restore one table for those). Kept rows count towards the database size. Turning the bin off stops keeping new deletes; rows already kept stay until they expire.

Restores run in the background and the page shows each step. Your project keeps working until the very end, when the restored database is swapped in and connections pause for a moment; Auth and the REST API restart. Changes made after the chosen backup or moment are lost.

#Who can do what

ActionRole
See backups and the recycle binEvery team member
Back up now, export, download, restore rows from the recycle binDeveloper and above
Restore, point-in-time recovery, restore one table, turn the recycle bin on or offAdministrator and owner

#Restore an export elsewhere

Terminal
pg_restore --no-owner --no-privileges -d "postgresql://localhost/mycopy" backup.dump

For extra safety you can also take your own dumps with pg_dump over a session-mode connection, or with stitchdb db dump.