Prisma seed data
Seed a Prisma + PostgreSQL app with FK-intact synthetic data, prisma migrate deploy, then one command. No seed.ts drift.
Prisma apps seed data through prisma/seed.ts: a script that usually grows a hand-written list of prisma.user.create() calls, or a faker-driven factory loop. It works until the schema changes and the seed stops matching it. This guide shows the Prisma-native seeding workflow, where it breaks, and the schema-driven alternative that removes the drift.
How Prisma seeding normally works
Prisma's built-in flow is prisma db seed, which runs the script declared in package.json:
{
"prisma": {
"seed": "tsx prisma/seed.ts"
}
}// prisma/seed.ts
import { PrismaClient } from "@prisma/client";
import { faker } from "@faker-js/faker";
const prisma = new PrismaClient();
async function main() {
for (let i = 0; i < 50; i++) {
await prisma.user.create({
data: {
email: faker.internet.email(),
name: faker.person.fullName(),
},
});
}
}
main();That works for a standalone users table. The problems start when relations appear.
Where Prisma seed scripts break
Three failure modes, in order of appearance:
- Foreign keys. Creating an
orderrequires auserid that doesn't exist yet. You either create the user first and capture the id (fine, but the script now encodes dependency order by hand), or you look it up (prisma.user.findFirst()), and when the table is empty or the lookup is wrong, the seed silently produces different data than you expect. - Schema drift. Add a NOT NULL column or a relation to
Userandseed.tsstops compiling or starts producing incomplete rows. Every schema change is a seed change, and the seed is the last file anyone updates. - Uniform randomness.
faker.internet.email()is fine for a demo. It is not a distribution: if 70% of your realstatusvalues areactive, a flat faker loop gives you roughly a third of each, and the query planner behaves differently than it will in production.
Schema-driven seeding with Weavori
Weavori reads the database schema, the same schema Prisma migrated, and generates rows from it. The Prisma-specific workflow:
Weavori introspects tables, foreign keys, and constraints, resolves the dependency order (parents before children), and writes via COPY. Every generated order.user_id references a real generated user, by construction, not by script logic.
The schema is the seed
When a Prisma migration changes the schema, the generated data changes with it. There is no seed.ts to update because nothing in the script duplicated the schema in the first place.
Prisma + Weavori in CI
The loop that keeps staging and test databases honest:
Weavori supports API keys for headless auth, standardized exit codes, and offline license validation. CI runners on restricted networks don't phone home. Full GitHub Actions / GitLab / CircleCI / Jenkins examples in the CI/CD guide.
Which Prisma seed command do you need?
| Goal | Command |
|---|---|
| Run the seed against a migrated database | npx prisma db seed |
| Rebuild the database from migrations, then seed | npx prisma migrate reset |
| Sync a schema with no migration history, then seed | npx prisma db push |
| Generate a production-shaped dataset with no seed script | npx --yes @weavori/cli generate postgres://localhost:5432/mydb |
npx prisma db seed
prisma db seed runs the script declared in the prisma block of package.json: conventionally prisma/seed.ts, executed through tsx:
{
"prisma": { "seed": "tsx prisma/seed.ts" }
}Prisma supplies the runner and the typed client, not the data. The rows come from that file, which is why the seed script becomes the thing you maintain: a list of prisma.user.create() calls, a Faker loop, or a custom generator. When the script is the only place the dependency order exists, a schema change is a seed change.
npx prisma migrate reset
prisma migrate reset drops the database, re-applies every migration, and runs the seed. It is the fastest route to a clean seeded database locally, and the reason a seed script has to stay runnable from an empty schema. In CI the equivalent loop is npx prisma migrate deploy followed by the seed step, or by a schema-driven generation step that replaces it.
npx prisma db push
prisma db push syncs your Prisma schema straight to the database without writing migration history, the fast path while the schema is still moving. It changes the schema only; the rows still come from seeding. Point Weavori at that same database afterwards and the generated data follows the schema you just pushed, with no seed.ts to update.
Does Prisma generate seed data?
No. Prisma gives you the runner and the typed client; the data comes from your script. That is the gap a schema-driven generator fills, the rows are generated from the schema itself, so there is no script to write and nothing to keep in sync when the schema changes.
When to keep your Prisma seed
Honesty about boundaries: keep prisma/seed.ts for deterministic unit-test fixtures: a known user with a known email that a test asserts against. @faker-js/faker remains the right tool for single values inside tests. Weavori replaces the dataset problem: filling dev, staging, and CI databases with production-shaped, FK-intact rows.
Related guides
- Postgres test data: the five ways to get test data, compared
- Postgres seed data generator: the tool comparison
- Postgres synthetic data: synthetic vs. mock vs. anonymized
- Drizzle seed data and TypeORM seed data: the same loop in other stacks
- Quickstart: first seed in minutes