An AI agent deleted data in Supabase: how to get it back

Supabase can restore a backup over your project, but that rolls back everything written since. Usually it's better to restore beside production and copy back only the rows the agent deleted.

The short answer

Stop the agent, then restore a backup into a new Supabase project at a point just before the delete, and copy the missing rows back into production. Supabase’s paid plans can restore a physical backup, or an exact point in time if Point-in-Time Recovery is on, into a separate project that is independent of the source.2 That keeps every good write made since the backup. Restoring over the live project is simpler, but the project is inaccessible while it runs and you lose what was written after the restore point.1

On the Free plan, Supabase recommends exporting your data yourself; if you have no export, there may be nothing to restore from.1

Deedglass reads what Postgres actually committed, not what the agent reported. In our demo a hidden trigger turned 1 row into 301; a person countersigned the undo and all 301 rows came back.

First: stop the agent and keep the evidence

Before restoring anything, make sure the agent can’t keep going. Revoke the key or role it used, close the session, and save its transcript and the database logs. Our first-hour checklist covers the order. If the agent held a secret or service_role key, it was past every policy you wrote; the service_role post explains why and how to rotate it.

Then write down two facts. The time of the delete, as precisely as you can (the agent’s transcript or the Postgres logs usually have it). And what it touched: which tables, roughly which rows.

What your plan can restore

Plan Daily backups Point-in-time recovery Restore into a new project
Free Not stated; Supabase recommends regular exports1 No No (paid plans only)2
Pro Last 7 days1 Add-on, needs at least a Small compute1 Yes2
Team Last 14 days1 Add-on1 Yes
Enterprise Up to 30 days1 Add-on1 Yes

Point-in-time recovery restores to any chosen point with granularity down to seconds, priced for 7, 14 or 28 days of retention.1 Without it, you pick the closest daily backup before the delete and accept whatever was written between that backup and the delete.

Two ways back

Restore over the project. Pick a backup or a point in time in the dashboard. Simple, and right when the agent damaged so much that the whole database is suspect. The costs: the project is inaccessible during the restore, so plan for downtime, and with daily backups you should “consider how many days of data you might lose.”1

Restore beside it, then copy back. Restore to a new project, find the deleted rows there, and insert them into production. Production stays up and keeps every write since. The new project copies the schema, data, roles and auth users, but not storage objects, Edge Functions, auth settings, API keys or database extension settings.2 For pulling rows out, that’s all you need.

One caution from Supabase’s docs: because the restore is binary, enabled extensions such as pg_cron or pg_net can start jobs as soon as the new project is up, and there’s no way to pause them during the restore.2 If a cron job sends emails or calls webhooks, the restored copy may send them again. Check what’s scheduled, and disable it in the copy the moment it’s ready, or use a logical restore with the CLI instead.

Worked example: copy back only the deleted rows

We ran this locally on PostgreSQL 18.6 with two databases standing in for the two projects: prod, where an agent deleted 300 of 500 orders, and restored, the copy from before the delete.

In production, the damage:

Code What the screen or file shows, copied as is.

DELETE 300

From the restored copy, export just the missing rows to a file:

Code A database command in SQL. The text around it says what it does.

\copy (select * from orders where id > 200) to 'orders.csv' csv

Code What the screen or file shows, copied as is.

COPY 300

In production, load them into a temporary table and insert only rows that aren’t already there, in one transaction:

Code A database command in SQL. The text around it says what it does.

begin;
create temp table recovered (like orders including all);
\copy recovered from 'orders.csv' csv
insert into orders select * from recovered on conflict (id) do nothing;
select count(*) from orders;
commit;

Code What the screen or file shows, copied as is.

COPY 300
INSERT 0 300
 count
-------
   500

Three choices in that script matter on a real project:

  • on conflict (id) do nothing skips any row that came back some other way, so the script is safe to re-run.
  • A temporary table lets you inspect what you’re about to insert before the insert runs.
  • One transaction means either every row returns or none do.

For a whole table, pg_dump --data-only -t <table> against the restored project’s connection string does the same export in one step. It dumps only the data, not the schema.3 When -t is used, pg_dump doesn’t dump the objects the table depends on, so load the output into a database that already has the schema.3

If the agent changed rows rather than deleting them, the same method works with insert ... on conflict (id) do update, but think first: a row the agent “damaged” may also have had a legitimate update since. Compare before you overwrite.

What a restore won’t bring back

  • Storage files. Database backups don’t include objects stored through the Storage API, and restoring an old backup doesn’t restore objects you deleted after that backup.1
  • Side effects outside the database. Emails sent, webhooks fired and payments made by the agent stay done.
  • Writes after the restore point, if you restore over the project instead of beside it.

Set this up before you need it

  • On Free, schedule your own exports with the Supabase CLI’s db dump.1
  • On Pro and above, decide whether Point-in-Time Recovery is worth its cost for the tables an agent can reach.
  • Give agents a development project or branch, not production. Our Supabase MCP checklist covers the settings.
  • Keep a record of what each agent session changed, so “which rows?” has an answer. Change-level undo is in undo for agent sessions.

Before connecting an agent at all, paste the agent’s MCP config into the check page or run npx deedglass scan (how the grade works) to see whether it can read a database URL without a prompt. To try the checks in your browser without installing anything, open the playground.

Questions people ask

Can Supabase restore a single table?

The backups page doesn’t describe single-table restores. Restoring into a new project and copying the table back, as above, gets you the same result without touching the rest of production.2

Does a Supabase restore cause downtime?

Restoring over the project does: the project is inaccessible during the process.1 Restoring into a new project leaves the original alone.2

Are Supabase Storage files included in backups?

No. Database backups don’t include objects stored through the Storage API.1

Written with AI assistance and checked against our claims register.

The takeaway

Restore a Supabase backup into a new project, then copy back only the rows the agent deleted; in our local run, 300 deleted rows went back in one transaction.

Read nextThe Supabase service_role key and AI agents: why it skips every policy Try it: install in 7 s

Related on this site

More posts

Sources

  1. 1Supabase docs: Database backups · supabase.com · checked 26 October 2026
  2. 2Supabase docs: Restore to a new project · supabase.com · checked 26 October 2026
  3. 3PostgreSQL docs: pg_dump · postgresql.org · checked 26 October 2026

Published 26 October 2026, sources last checked 26 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing