The short answer
If the delete happened inside your project’s history window, Neon can get the data back. You have three tools: instant restore, which reverts a root branch to an earlier point and keeps the pre-restore state in a backup branch; a branch from a past point, from which you copy back only the lost rows; and snapshots, if you took or scheduled one.143
Copying rows back keeps every legitimate write since the delete. Restoring the whole branch is faster to do but rolls back everything after the chosen point. Either way, look at the past state first with a read-only query before you change anything.
Stop the agent before any of this. Our first-hour checklist covers revoking its access and keeping the evidence.
Deedglass
A database change, checked and put back
-
1The agent’s change
Change order 42
UPDATE orders … WHERE id = 42
The agent: “1 row updated” -
2What the database really did
301 rows
A hidden trigger changed 300 more
Doesn’t match -
3Put back
301 rows restored
Signed off by a person
Matches
Check your history window first
Instant restore, Time Travel queries, branching from the past and snapshots all rely on Neon keeping a history of changes, and the length of that history depends on your plan:2
| Plan | Default history window | Maximum |
|---|---|---|
| Free | 6 hours | 6 hours, capped at 1 GB of history |
| Launch | 1 day | 7 days |
| Scale | 1 day | 30 days |
On Launch and Scale, history storage is billed separately from branch storage, so a longer window costs more.2
Read the Free row twice. If an agent deleted data on a Free project and nobody noticed for seven hours, the history is gone. The default window on paid plans is one day unless you raised it. If you’re reading this before anything went wrong, raise the window on any project an agent can write to.
Find the moment before the delete
Neon’s Time Travel Assist lets you run read-only queries against a past point in your history window, to confirm the exact restore target before you restore.1 Use it to bracket the delete:
- Take the time from the agent’s transcript or your logs.
- Query the table a minute before that time. Are the rows there?
- Query a minute after. Are they gone?
- Narrow until you have a point where the data is intact and nothing legitimate is missing.
Write that timestamp down. Every option below uses it.
Option 1: instant restore of the branch
Instant restore reverts a root branch to an earlier point in its own history, or another root branch’s history. Child branches don’t support it.1 From the CLI:
Code Commands typed in a terminal. The text around it says what happens.
neon branches restore <target id|name> <source id|name @ timestamp|lsn>
The API equivalent is POST /projects/{project_id}/branches/{branch_id_to_restore}/restore.1
What happens:
- Existing connections to the branch are interrupted during the restore; connection details stay the same, so applications reconnect afterwards.1
- Neon keeps the pre-restore state in an automatically created backup branch named
{branch_name}_old_{head_timestamp}.1
That backup branch is your safety net. Every write between the restore point and the restore is in it. If customers placed orders in that gap, you now have to copy them forward from the backup branch, which is Option 2 in reverse.
Option 2: copy back only what was lost
Create a branch from the past point (a Neon branch is a copy-on-write clone that can start from a current or past state without load on the parent4), then move the missing rows into production yourself.
Point a psql session at the past branch and export the rows the agent deleted:
Code A database command in SQL. The text around it says what it does.
\copy (select * from orders where id between 201 and 500) to 'orders.csv' csv
Then, connected to production, load them into a temporary table and insert 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;
commit;
We ran exactly this pattern on a local PostgreSQL 18.6 for 300 deleted rows; the details are in our Supabase restore post, and it is the same SQL on Neon. For a whole table, pg_dump --data-only -t orders from the past branch exports only the data; pg_dump doesn’t include the objects a table depends on when -t is used, so load into a database that already has the schema.5
When you’re done, delete the recovery branch. If you might need it again, reset it from its parent instead.4
Option 3: restore from a snapshot
Snapshots capture a branch’s state at a point in time. You can take one by hand or schedule them daily, weekly or monthly; manual snapshots are allowed on all plans (one on Free, 100 on paid plans), and automated schedules are on paid plans.3
A restore from a snapshot comes in two forms:3
- One-step: the snapshot’s data replaces the branch in place. The name and connection string stay; the branch ID changes, and the previous branch is kept as
<branch_name> (old). In the API this isfinalize_restore: true. - Multi-step: a new branch is created from the snapshot so you can inspect it, then you finalize to swap it in. In the API this is
finalize_restore: false, then the finalize call.
Use multi-step when an agent is involved. You want to look before you swap. Note one limit: instant restore isn’t currently supported on branches created from a snapshot restore.3
Which one to use
| Situation | Use |
|---|---|
| The agent deleted rows in a few tables; real users kept writing | Option 2: copy back |
| The agent ran destructive DDL or changed data everywhere, and the branch is suspect | Option 1: instant restore, then copy forward any good writes from the _old_ branch |
| The delete is older than your history window | Option 3, if a snapshot exists from before it |
| It’s a development branch | Reset it from its parent4 or recreate it |
Before the next time
- Raise the history window on projects agents can write to, within what you’re willing to pay.
- Schedule snapshots on paid plans, so a delete noticed late is still recoverable.
- Give agents a child branch, not the production branch. The Neon MCP server post has a setup with
projectIdand read-only mode. - Record what each agent session changed, so the “which rows?” question has an answer. Undo for agent sessions shows a change-log approach.
To see whether an agent on your machine can read a database URL without a prompt, paste the agent’s MCP config into the check page or run npx deedglass scan (how the grade works); the scan Action does the same on each pull request. To try the checks in your browser without installing anything, open the playground.
Written with AI assistance and checked against our claims register.