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.
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.