How Do I Clear Out Seed and Test Data Before Real Users Arrive?
6 min read
Before real users arrive, you want to remove the fake data your agent created, but only the fake data. The safe way is to take a backup, identify the seed rows by a marker you can trust, delete them in a transaction, and verify the counts, rather than wiping the whole database and hoping. Done carelessly, a "clean up the test data" command deletes the wrong rows and there is nothing to sign up into.
Why this happens
To make your app look alive in the demo, your AI agent seeded it: a handful of
fake users, some dummy orders, a few test@test.com logins, lorem-ipsum posts.
That was the right call for building. It becomes a problem the moment real people
show up, because fake accounts skew your numbers, dummy orders can trigger real
emails, and a test@test.com with a known password is an open door.
The agent built what you asked for ("give me some sample data so I can see it working") and never built the part you didn't ask for: a clean, reliable way to remove it later. So the seed rows sit in your production database with no label saying which ones they are.
How to check
Find out what you are dealing with before you delete anything.
-
Count your rows. In the Supabase or Firebase console, open each table and look at the row count. If your "live" app has 47 users and you have shown it to nobody, most of those are seed rows.
-
Search for the obvious markers. Look for the strings your agent tends to reuse:
test@,example.com,@test.com,lorem,John Doe,Jane Doe,foo,bar,123456. In Supabase SQL editor:select id, email, created_at from users where email ilike '%test%' or email ilike '%example.com%'; -
Check the timestamps. Seed rows are usually all created within the same few seconds, long before today. Sort each table by
created_atand the seed batch stands out as a clump.
The fix
-
Back up first. Take a full backup or snapshot of the database (Supabase: Database, Backups; or
pg_dump). This is the single step that turns a mistake into an inconvenience. See do I need database backups before beta launch. -
Preview with a SELECT before you DELETE. Run the exact
whereclause as aselectfirst and read the rows. Only when you are sure they are all fake do you changeselect *todelete. -
Delete in a transaction so you can back out. Wrap it so a wrong count can be undone:
begin; delete from orders where user_id in (select id from users where email ilike '%example.com%'); delete from users where email ilike '%example.com%'; -- check the row counts printed back commit; -- or: rollback;Delete child rows (orders, posts, comments) before the parent users, or a foreign-key constraint will stop you.
-
Handle the auth table too. On Supabase, deleting from your
userstable does not remove the login inauth.users. Delete those test logins from Authentication, Users in the dashboard, or they can still sign in. -
Reset any demo counters. If you seeded stats, waitlist numbers, or "1,024 signups" copy, set them back to real values.
-
Verify. Re-run your marker searches and the row counts. They should return nothing and match reality.
The trap to avoid
Do not "reset" production by truncating every table or re-running the seed
script with a wipe step. That is how founders delete the one real account they
made, their own admin login, or a paying tester. The goal is surgical removal of
known-fake rows, not a factory reset. And never run a raw delete without a
where clause; one missing line empties the whole table.
Where this fits
A database full of test@test.com is one of the clearest signs an app is demo-ready
but not launch-ready, and it is easy to miss because everything still works. The
free Readiness Report runs your own agent across your real project and
flags leftover seed rows, fake logins, and placeholder copy before a real user
sees them. If a delete goes wrong, how to restore your database
covers the recovery, and leftover fake demo data in my app
covers the version of this that shows up in the UI. When you want the whole
cleanup handed to you in order, that is what the Finishing Pass is for.