Back to Blog

Prisma Seed Script Not Running in CI/CD Pipeline

Published: July 28, 2026
Prisma Seed Script Not Running in CI/CD Pipeline

Prisma seed script not running in CI/CD almost never means the seed file itself has a logic bug — it runs fine locally, inserting exactly the reference data you expect. In CI, it either fails outright with an error about a missing command, or worse, does nothing at all with no error, leaving a freshly migrated database with no data and a pipeline that reports green. Both symptoms trace back to the same root cause: something environment-specific that never shows up when you're running the seed script on your own machine.

Short answer: check whether your CI pipeline actually calls prisma db seed explicitly — current Prisma versions no longer trigger seeding automatically as part of migrate dev or migrate deploy — and separately confirm the TypeScript runner your seed command depends on (tsx, or the older ts-node) is actually installed in the CI environment, not just on your laptop. Two different failure modes, both invisible until you look at exactly what the CI job runs versus what you assumed it ran.

Elderly hands holding soil with seeds under sunlight, representing the reference data a seed script is meant to plant into a freshly migrated database

Why Prisma's Seed Step Silently Gets Skipped in CI

The quieter of the two failure modes is the more common one: your pipeline was written assuming prisma migrate deploy (or migrate dev, in an older setup) would seed the database as a side effect, because that used to be true. Current Prisma versions deliberately removed that coupling — seeding is only triggered explicitly by running npx prisma db seed, and running a migration no longer does it for you. If your CI YAML has a prisma migrate deploy step and nothing calling db seed afterward, the pipeline completes successfully, reports no errors, and simply never seeds anything — because nothing in the pipeline ever asked it to.

(If you've been re-reading your seed script for a bug that would explain "nothing happened" — there isn't one to find. A script that's never invoked doesn't fail. It just doesn't run.)

Fix 1: Make db seed an Explicit CI Step, in the Right Order

The direct fix is adding the seed command explicitly, after migrations have actually completed:

YAML
1# .github/workflows/deploy.yml
2- name: Run database migrations
3  run: npx prisma migrate deploy
4
5- name: Seed the database
6  run: npx prisma db seed

Order matters here specifically because a seed script assumes the schema it's inserting data against already exists — running seed before or in parallel with migrations means it's writing against tables and columns that may not be fully created yet, which produces errors that look like a broken seed script but are actually a race condition in step ordering.

Fix 2: Configure the Seed Command Correctly, and Confirm the Runner Is Actually Installed

Prisma's current seeding documentation configures the seed command directly in prisma.config.ts rather than an older package.json field, and recommends tsx over ts-node:

TypeScript
1// prisma.config.ts
2import 'dotenv/config';
3import { defineConfig } from 'prisma/config';
4
5export default defineConfig({
6  schema: 'prisma/schema.prisma',
7  migrations: {
8    path: 'prisma/migrations',
9    seed: 'tsx prisma/seed.ts',
10  },
11});

The classic version of this bug — ts-node ENOENT or an equivalent "command not found" for whichever runner you're using — happens when that runner is listed only under devDependencies, and CI installs with a flag that skips dev dependencies for a production build. Prisma's own GitHub discussion on this exact ts-node/seed interaction has several teams' variations of the same root cause if your specific error text doesn't match what's shown here. The fix is either installing with dev dependencies included for the job that runs seeding, or making sure tsx (or ts-node) is available wherever prisma db seed actually executes:

JSON
1// package.json
2{
3  "devDependencies": {
4    "tsx": "^4.0.0"
5  }
6}
Bash
1# CI install step — include dev dependencies if the seed step needs tsx to exist
2npm ci --include=dev

npm's own npm ci reference documents exactly what --include=dev and its related flags control, worth a direct check if your CI install step was copied from a production-optimized template that predates adding a seed step at all.

A rusty vintage toolbox sitting among scrap metal, representing a CI environment missing the TypeScript runner the seed command actually depends on

Fix 3: Make the Seed Script Idempotent

A seed script that assumes a completely empty database breaks the moment CI runs against a persistent environment — a shared staging database, for instance — that already has seed data from a previous run:

TypeScript
1// prisma/seed.ts — idempotent: safe to run once or a dozen times
2import { PrismaClient } from '@prisma/client';
3
4const prisma = new PrismaClient();
5
6async function main() {
7  await prisma.plan.upsert({
8    where: { slug: 'starter' },
9    update: {},
10    create: { slug: 'starter', name: 'Starter', priceMonthly: 2900 },
11  });
12}
13
14main()
15  .catch((error) => {
16    console.error(error);
17    process.exit(1);
18  })
19  .finally(async () => {
20    await prisma.$disconnect();
21  });

upsert() in place of create() means the same seed run against a database that already has this row updates it harmlessly instead of throwing a unique-constraint violation — which is exactly the behavior a CI/CD pipeline needs from a step that might run against the same environment more than once.

Domino blocks lined up in a precise row, representing seed and migrate steps that need to run in the correct order, not in parallel

The Opinion Part

Here's the pattern worth naming, because it's the quiet theme running through nearly every bug in this Prisma sub-series: a tool's behavior changing between major versions is a completely reasonable thing for a maintainer to do, and it's also exactly the kind of change that turns a pipeline written two years ago into one silently doing less than the team believes it's doing. Teams already spend an estimated 33-42% of their time servicing technical debt rather than shipping features (Stripe Developer Coefficient) — a CI pipeline that assumes yesterday's tool behavior is precisely the kind of debt that doesn't show up on any dashboard until someone notices a staging environment has been running with no reference data for months. The fix isn't just adding the missing step. It's treating "does our pipeline still do what we think it does" as a question worth actually re-checking after any major dependency upgrade, not just after something visibly breaks.

Conclusion

If Prisma's seed script isn't running in CI, check two things before touching the seed file itself: whether your pipeline explicitly calls prisma db seed at all now that migrations no longer trigger it automatically, and whether the TypeScript runner the seed command depends on is actually installed in the environment executing it. Get the order right — migrate first, seed second — and make the seed script idempotent so it survives running against an environment that isn't perfectly empty.

If migrations themselves are the part still causing CI trouble on a managed database, our shadow database permission guide and our migration drift guide both cover adjacent failure modes in the same pipeline.

Add the explicit seed step, install the runner where CI actually needs it, and watch a fresh environment come up with real reference data instead of an empty, technically-successful deploy.

Frequently Asked Questions

In current Prisma versions, seeding is deliberately decoupled from prisma migrate — running migrate dev or migrate deploy no longer automatically triggers a seed the way older versions did. If your CI pipeline was written assuming migrate would seed the database as a side effect, it simply won't anymore, and unless you add an explicit npx prisma db seed step, nothing happens and nothing errors either, because the pipeline never asked for it.

It means the TypeScript runner your seed command depends on isn't actually installed in the CI environment executing it — commonly because ts-node (or its current recommended replacement, tsx) was only ever installed as a devDependency, and the CI job's install step skipped dev dependencies. The seed command references a binary that plain doesn't exist in that environment, which fails immediately rather than running anything.

Prisma's own current documentation recommends tsx over ts-node for running a TypeScript seed file, configured directly in prisma.config.ts rather than a package.json field. tsx tends to have fewer of the ESM/CommonJS interop issues that historically caused ts-node-specific seed failures, though the underlying 'is the runner actually installed where CI expects it' problem applies to either choice equally.

A seed script almost always assumes the schema it's inserting data against already exists — tables, columns, and constraints created by your migrations. Running seed and migrate in parallel, or seed before migrate completes, means the seed script is writing against a schema that may not be fully in place yet, producing errors that look like a seed script bug but are actually a race condition in pipeline ordering.

Yes, strongly recommended. A CI pipeline that runs against a database that already has seed data from a previous run — a persistent staging environment, for instance — will fail on unique constraint violations if the seed script uses create() everywhere. Writing the seed script with upsert() instead means running it once or a dozen times produces the same result, which is what a CI/CD pipeline actually needs from a repeatable step.

Portrait of Umar Farooq

About Umar Farooq

Umar Farooq is the founder and lead engineer of Codify SaaS. He builds B2B SaaS products and web applications on modern TypeScript stacks and enterprise Java, and writes code-first guides drawn from real production work — the schema decisions, the migrations that almost went wrong, and the performance fixes that actually moved the numbers. When he recommends an approach, he shows the code and explains the trade-offs.

Read full bio