Most teams eventually end up with a seed.ts or seed.sql file. It starts as a convenience. Then it slowly picks up more and more setup work.
Copy Code
You run migrations, load fixtures, wait for some background job to process things, and then hope nothing has drifted since the last time someone touched it.
I still want every new environment to be isolated and fresh. But I don't think "fresh" has to mean building everything from scratch. The question for me was whether you could get that same fresh, isolated environment without recreating all the data every time.
Note: We open-sourced Xata under Apache 2.0. This post explores the workflow that copy-on-write branching unlocks. If you want to see how it works under the hood or run it yourself, the announcement post and technical deep dive cover the internals.
Why we seed
Seeding earned its place. It's portable, repeatable, and fits the "infra from scratch" mindset. For a small app with 20 rows of fixture data, it's genuinely the simplest thing that could work. For tests that need to start from a known state every time, it's still the right tool.
The problems start showing up when:
Fake data misses real edge cases. A seed might have 2 users. Production might have 200,000, plus nulls in places you didn't expect, foreign keys left behind by an old migration, and plan types your current enum doesn't even have anymore.
A seed might have 2 users. Production might have 200,000, plus nulls in places you didn't expect, foreign keys left behind by an old migration, and plan types your current enum doesn't even have anymore. Seed scripts become another thing to maintain. Every migration needs a seed update. Every new feature needs fixture data. The file gets longer and it gets harder to tell what is still needed.
... continue reading