<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 "> Seeding

Seeding

This course covers the three places data lives in a typical backend: databases, storage buckets, and a key/value cache. We start with databases, and three things that make working with one reliable and fast: loading a known starting set of data, grouping writes so they can't half-finish, and speeding up the reads you do most.

Seeding is filling a database with a known starting set of data. You write a script once, then run it whenever you need that baseline back: a fresh local setup, a test run, or a demo. It's setting the table before guests arrive. Everything is in a predictable place before anyone sits down to eat.

Common reasons you may need one

  • Local development, so every engineer starts from the same data
  • Automated tests that need predictable rows to assert against
  • Demos and staging environments that should look "real"
  • Production reference data that ships with the app and rarely changes, like country codes, roles, or plan tiers, seeded on deploy so every environment starts from the same rows.

How to use it

Prisma runs a seed script through a small bit of config in package.json:

{
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  }
}

The script itself uses the Prisma client directly:

// prisma/seed.ts
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

async function seed() {
  // upsert keeps the seed idempotent: insert if missing, update if present
  const ada = await prisma.user.upsert({
    where: { email: "ada@example.com" },
    update: {},
    create: { name: "Ada", email: "ada@example.com" },
  });

  await prisma.post.createMany({
    data: [
      { title: "Hello world", authorId: ada.id },
      { title: "Second post", authorId: ada.id },
    ],
    skipDuplicates: true,
  });
}

seed()
  .then(() => prisma.$disconnect())
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });

Run it with npx prisma db seed. Prisma also runs this automatically after prisma migrate reset and when it creates a fresh dev database, so a reset always lands you back on the same baseline.

Idempotence

A seed should be idempotent: running it once or five times leaves the database in the same state. Without that, the second run either errors on a unique constraint or piles up duplicate rows. Two ways to get there:

  • Clear first — delete the tables the seed owns, then insert fresh.
  • Upsert — insert the row if it's missing, update it if it already exists, keyed on a unique field like email.

Keep the data small and meaningful. It's a starting point, not your production dataset.

seed.ts upsert by email run once run five times users table ada@example.com linus@example.com always exactly two rows
An idempotent seed lands on the same rows whether you run it once or five times. upsert inserts what's missing and updates what's already there.

Exercise

Node challenge · runs in your browser

Make the seed idempotent

Make this seed idempotent: running it twice should leave exactly two users, not four. Swap the create call for the operation that inserts a row if it's missing and updates it if it already exists, keyed on the unique email.

A mock Prisma client is provided in prisma.js so the tests run without a real database.