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.
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
- Drizzle seed data — the same loop in the Drizzle ecosystem
- Quickstart — first seed in minutes