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:

  1. Foreign keys. Creating an order requires a user id 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.
  2. Schema drift. Add a NOT NULL column or a relation to User and seed.ts stops compiling or starts producing incomplete rows. Every schema change is a seed change, and the seed is the last file anyone updates.
  3. Uniform randomness. faker.internet.email() is fine for a demo. It is not a distribution: if 70% of your real status values are active, 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:

1. Migrate (or db push) as usual
$ npx prisma migrate deploy
2. Seed from the schema
$ npx --yes @weavori/cli generate postgres://localhost:5432/mydb --rows 1000

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:

$ npx prisma migrate deploy
$ npx --yes @weavori/cli generate $TEST_DATABASE_URL --rows 1000 --output plain

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?

GoalCommand
Run the seed against a migrated databasenpx prisma db seed
Rebuild the database from migrations, then seednpx prisma migrate reset
Sync a schema with no migration history, then seednpx prisma db push
Generate a production-shaped dataset with no seed scriptnpx --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.

1. Push the schema (no migration history)
$ npx prisma db push
2. Generate FK-intact rows from that schema
$ npx --yes @weavori/cli generate postgres://localhost:5432/mydb --rows 1000

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.

Ready to generate your first dataset?

Install Weavori in one command and connect to any PostgreSQL database.

$npm install -g @weavori/cli
macOS · Linux · Windows/No dependencies required

No credit card required. Start with a 14-day free trial of Pro, then free tier or subscribe.