PresentationInteractive, narrated presentation of the section content.
ContentDetailed description of the section content.
Motivation
Welcome, everyone! Today, we’re diving into an essential part of building real-world applications: seeding data and handling migrations using Prisma.js. Why does this matter? Imagine you’re creating a blogging app—like the one we’ll build together in this lecture. You want users to see posts right away and admins to manage them, but how do you set up that initial data? And what happens when your app evolves, and you need to change your database structure? That’s where seeding and migrations come in—they’re the backbone of keeping your database organised and functional.
Let’s start with a relatable problem: You’ve built a blog app, but when you launch it, the homepage is empty—no posts! Users leave, frustrated. Seeding fixes that by populating your database with starter data. Now, imagine you decide to add a "tags" feature to filter posts, but your database doesn’t know about tags yet. Migrations let you update your database safely without breaking everything. These tools are critical for any developer, and mastering them will save you headaches down the road.
Here’s a common misconception: “I’ll just manually add data or tweak my database when I need to.” That works for a tiny project, but in the real world, you need a systematic approach with teams and live users. Let’s bust another myth: “Migrations are scary and might delete my data.” Done right, they’re safe and powerful. Ready to see how? Let’s jump in with our blog app example.
🛳️ Understanding Prisma Migrations
First, let’s tackle migrations. Prisma is an ORM (Object-Relational Mapping) tool that makes working with databases easier. Migrations are how Prisma keeps your database schema in sync with your code. Think of it like updating the blueprint of a house as you add new rooms. Prisma offers two main commands for this: migrate and db push. Let’s explore both using our blog app.
How Migrations Work
We will start with a simple schema in schema.prisma:
model Post {
id Int @id @default(autoincrement())
title String
content String
createdAt DateTime @default(now())
}To apply this to your database, you have two options:
Option 1: <strong>prisma migrate dev</strong>
Run:
pnpx prisma migrate dev --name initThis creates a migration file (e.g., 20250310120000_init) in a migrations folder. It’s a SQL script that tells your database (like PostgreSQL) to create the Post table. Prisma tracks every change in these files, building a history of your database’s evolution. Now, let’s add tags:
model Post {
id Int @id @default(autoincrement())
title String
content String
createdAt DateTime @default(now())
tags String[]
}Run:
npx prisma migrate dev --name add_tagsPrisma compares the old schema to the new one, generates a new migration file to add the tags column, and applies it. Existing posts get an empty tags array by default. This is great for production apps because it’s controlled, repeatable, and reversible.
Option 2: <strong>prisma db push</strong>
Instead, you could run:
npx prisma db pushThis directly updates your database to match the schema—no migration files, no history. After adding tags, run it again, and the database instantly reflects the change. It’s faster but less structured.
Key Differences: <strong>migrate</strong> vs. <strong>db push</strong>
- Tracking:
migrate devcreates a versioned history (migration files);db pushdoesn’t—it just syncs the database. - Use Case: Use
migrate devfor team projects or production where you need control and rollback options. Usedb pushfor quick prototyping or solo development. - Safety:
migratelets you review and tweak changes before applying;db pushapplies them immediately, which can risk data loss if you’re not careful (e.g., dropping a column deletes its data). - Example in Action: For our blog app,
migrate devensures we can share schema changes with a team and deploy safely. Withdb push, we’d skip the paperwork but lose the ability to undo mistakes.
Step-by-Step Example with Both
- Initial Setup: Define the
Postmodel and runnpx prisma migrate dev --name init. The table is created with a migration file. - User Feedback: “Add tags to filter posts!” Update the schema with
tags. - Migrate Path: Run
npx prisma migrate dev --name add_tags. A new migration file adds the column, and we’re ready for production. - Push Path: Alternatively, run
npx prisma db push. The database updates instantly—no files, no fuss, but no history either. - Result: Both get us a
tagscolumn, butmigrategives us structure, whilepushgives us speed.
Advantages and Disadvantages
- Migrate:
- Pros: Version control, safe for teams, rollback possible.
- Cons: Slower setup, requires managing migration files.
- Db Push:
- Pros: Fast, simple, great for testing.
- Cons: No history, riskier for production, harder to collaborate.
🌱 Seeding Data with Prisma
Now, let’s populate our blog with data using seeding. Seeding means preloading your database with initial data—like sample posts—so it’s not empty when users arrive.
How It Works
Create a seed.ts file in the prisma folder:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
await prisma.post.createMany({
data: [
{ title: "My First Post", content: "Hello, world!", tags: ["intro"] },
{ title: "Tech Trends", content: "AI is the future.", tags: ["tech"] },
],
});
}
main()
.then(() => prisma.$disconnect())
.catch((e) => {
console.error(e);
prisma.$disconnect();
process.exit(1);
});
Update package.json:
"scripts": {
"prisma:seed": "ts-node prisma/seed.ts"
}
After migrating (or pushing), run:
npm run prisma:seed
Your database now has two posts, ready for users to filter by tags.
Expanding the Example
For a more complex seed, add dates and more tags:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
await prisma.post.deleteMany(); // Clear existing data (optional)
await prisma.post.createMany({
data: [
{
title: "My First Post",
content: "Hello, world!",
createdAt: new Date("2025-01-01"),
tags: ["intro", "welcome"],
},
{
title: "Tech Trends",
content: "AI is the future.",
createdAt: new Date("2025-02-15"),
tags: ["tech", "innovation"],
},
{
title: "Travel Diary",
content: "Exploring the mountains.",
createdAt: new Date("2025-03-01"),
tags: ["travel", "nature"],
},
],
});
console.log("Database seeded!");
}
main()
.then(() => prisma.$disconnect())
.catch((e) => {
console.error(e);
prisma.$disconnect();
process.exit(1);
});
Run it again, and your app has a rich starting point.
Advantages and Disadvantages
- Advantages: Quick setup, consistent test data, easy to tweak.
- Disadvantages: Can overwrite data if not careful, and large seeds slow things down.
Section 3: Putting It Together in Our Blog App
Our blog app ties migrations and seeding together:
- Client Side: Users filter posts by tags (e.g.,
/posts?tag=travel). - Admin Side: Admins add/edit posts.
Workflow
- Define the schema in
schema.prisma. - Use
migrate devfor production ordb pushfor prototyping to apply changes. - Seed data with
npm run prisma:seed. - Query posts with Prisma’s client:
const posts = await prisma.post.findMany({
where: { tags: { has: "tech" } },
});
Real-World Twist
“Won’t db push break my app?” Only if you’re reckless—test first! “Seeding feels fake!” It’s a standard way to mimic real usage.
Conclusion
Today, we mastered Prisma migrations and seeding for our blog app.
- Key Takeaways:
migrate devfor structure,db pushfor speed, seeding for instant data. - Best Practices: Use
migratein teams, testdb pushcarefully, keep seeds realistic. - Pitfalls: Don’t mix
migrateandpushcarelessly, avoid untested schema changes.
You’re ready to build a dynamic blog app. Next, we’ll query this data to power your features. Great job—keep exploring Prisma!
No hints available.