Postgres seed data generator: fill your database without writing INSERTs
Seeding a PostgreSQL database means populating an empty schema with initial rows. The tool you choose decides how much time you spend on foreign keys, maintenance, and broken fixtures. This guide compares the options and shows the schema-driven approach that removes the work entirely.
A Postgres seed data generator is a tool that populates an empty database with initial rows. The options range from hand-written SQL scripts to ORM seeders to schema-driven generators that read your tables and foreign keys and produce referentially intact rows automatically. This guide compares the approaches, says honestly when each one fits, and shows the schema-driven workflow that removes the work entirely.
What is database seeding?
Seeding is the step after migrations: the schema exists, and you need rows in it, for local development, staging, demos, or CI. The rows have to respect the schema's rules: foreign keys must point at real parents, NOT NULL columns must be filled, and CHECK constraints must pass.
The difficulty of seeding scales with schema complexity. A three-table demo is trivial to seed by hand. A schema with composite primary keys, multi-level foreign key chains (users → orders → order_items), enums, and CHECK constraints is where hand-written seeds fall apart.
Four ways to seed a PostgreSQL database
| Approach | FK handling | Setup cost | Maintenance | Best for |
|---|---|---|---|---|
Hand-written SQL (INSERT, generate_series()) | Manual | Hours per table | Breaks on schema change | Throwaway demos |
ORM seeders (prisma db seed, rake db:seed, factory_boy) | Manual | Per-model code | Drifts from the schema | Unit-test fixtures |
Dump and restore (pg_dump) | Native | Trivial | PII risk, stale, heavy | Literal prod copies |
| Schema-driven generator (Weavori) | By construction | One command | Zero, follows the schema | Anything with foreign keys |
Honest guidance:
- Hand-written SQL is fine while your schema fits in one file. The day a foreign key chain appears, you start writing inserts in dependency order, and re-verifying them after every migration.
- ORM seeders are convenient because they live in your codebase, but they duplicate schema knowledge. When the schema changes and the seeder doesn't, your fixtures silently drift. Faker and factory_boy are excellent for single values; they do not resolve relationships for you.
- Dump and restore is the most faithful, exactly your data, including the PII. That's also why it's the wrong tool for most dev, staging, and CI environments. It is also the wrong recovery model for data you could rebuild: see Backups are for data you cannot regenerate.
- Schema-driven generation reads the schema as the source of truth, so seeding can't drift from it. This is the approach Weavori takes.
The deciding question: who should own the knowledge of how rows relate, your seed script, or the schema? The schema is always right. Seeders that re-encode it are always one migration behind.
Why foreign keys break seed scripts
Foreign keys are the hardest part of seeding, for a mechanical reason: children must reference parent rows, and parent IDs are not known until the parents are inserted.
Hand-written scripts handle this three ways, all fragile:
- Hard-coded IDs: breaks the moment an insert order changes or an ID sequence differs
- Query the parent after inserting: works, but doubles the script length and the drift surface
- Skip the constraint: guarantees you will hear about it in a test failure, later
Schema-driven generators handle it by construction: they read the foreign keys, compute the dependency order (parents before children), and stream a cache of generated parent IDs. Every row references a real parent, no manual ordering, no lookups, no hard-coded IDs.
How Weavori seeds a PostgreSQL database
Three steps, none of them writing SQL:
- Connect: point Weavori at the database, or paste
CREATE TABLEstatements (DDL paste mode) when the schema isn't deployed yet - Plan: Weavori introspects tables, foreign keys, types, and constraints, then shows a preview: estimated rows per table, generator choices, fallbacks
- Generate: parents before children, via PostgreSQL COPY, with constant-memory streaming
Row counts are per-table configurable. Custom CSV datasets, computed-column formulas, and table exclusions all work without touching SQL.
Seeding speed is not a trade-off
Typical schemas (under 200 tables) seed in under 2 minutes. Benchmarks: 100,000 rows across 14 tables in 12.4 seconds, 25,000 rows in 2.1 seconds (Dockerized PostgreSQL 17, generation via COPY, July 2026).
Seeding in CI
Seeding belongs in the pipeline, not in a developer's local shell history. In CI the requirements change: headless authentication, parseable output, deterministic exit codes, and no phone-home licensing.
Weavori supports API keys for headless auth, plain and json output, standardized exit codes, and a schema cache so repeat seeds skip introspection. Licenses validate offline: CI runners on restricted networks don't phone home. See the CI/CD guide for GitHub Actions, GitLab, CircleCI, and Jenkins examples.
Seeding vs. syncing
Seeding generates fresh rows for an empty database. Syncing copies real rows between databases in FK-safe order. Weavori's Pro sync command. If you need an exact copy of existing data (a staging mirror, a demo of real records), sync is the tool. If you need new data that behaves like production, seed.
Seeding in your framework
A seed data generator that reads the schema behaves the same way in every stack, the framework's own seeder is the part that changes. These guides cover each framework's seeding commands, where they break, and what replacing them looks like:
- Prisma seed data:
npx prisma db seed, and whyseed.tsdrifts - Drizzle seed data:
npx drizzle-kit pushanddrizzle-seed - TypeORM seed data:
npx typeorm migration:runplus a hand-written seed script - Django seed data:
python manage.py loaddataand fixture files - Rails seed data:
rails db:seedandrails db:seed:replant - Laravel seed data:
php artisan migrate --seedand model factories
Related guides
- Mockaroo alternative: a schema-driven generator next to Mockaroo's field form
- Postgres test data: the five ways to get test data, compared
- Postgres synthetic data: synthetic vs. mock vs. anonymized
- How to generate realistic test data for PostgreSQL: the five practices, in depth
- Quickstart: first seed in minutes
- Comparison hub: Weavori against other tools, honestly