Skip to content

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.

  1. 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.

  2. 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%';
    
  3. Check the timestamps. Seed rows are usually all created within the same few seconds, long before today. Sort each table by created_at and the seed batch stands out as a clump.

The fix

  1. 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.

  2. Preview with a SELECT before you DELETE. Run the exact where clause as a select first and read the rows. Only when you are sure they are all fake do you change select * to delete.

  3. 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.

  4. Handle the auth table too. On Supabase, deleting from your users table does not remove the login in auth.users. Delete those test logins from Authentication, Users in the dashboard, or they can still sign in.

  5. Reset any demo counters. If you seeded stats, waitlist numbers, or "1,024 signups" copy, set them back to real values.

  6. 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.