When developing applications with Next.js and Prisma, one common challenge is creating seed data for your database. This process can be particularly tricky when working with TypeScript and the latest Next.js features like the App Router. In this blog post, we'll explore an effective approach to generating seed data for your Next.js and Prisma-based projects.
The Challenge
Our scenario involves:
- A project using TypeScript, Next.js (with App Router), and Prisma
- PostgreSQL as the database
- Using
prisma migrate
for database migrations
The main issue arises when trying to run TypeScript files for seeding data, as the default Next.js configuration doesn't always play nicely with this process.
The Solution
After researching various approaches, we found a solution that doesn't compromise Next.js's recommended settings. The key is to create a separate TypeScript configuration file specifically for seeding data.
Step 1: Set Up the Environment
First, ensure you have ts-node
installed:
pnpm add -D ts-node
Step 2: Create a Local TypeScript Configuration
Create a tsconfig.local.json
file in your project root. You can start by copying your existing tsconfig.json
:
cp tsconfig.json tsconfig.local.json
Then, modify tsconfig.local.json
:
{
"compilerOptions": {
// ... other options remain the same
"module": "commonjs"
}
}
Step 3: Update package.json
Add a prisma.seed
script to your package.json
:
{
// ... other configurations
"prisma": {
"seed": "ts-node --project tsconfig.local.json prisma/seeds/main.ts"
}
}
Step 4: Organize Your Seed Files
Structure your seed files like this:
prisma/
migrations/
seeds/
0_users.ts
1_books.ts
main.ts
schema.prisma
Step 5: Write Your Seed Logic
Here's an example of how to structure your seed files:
0_users.ts
:
import type { PrismaClient } from "@prisma/client";
const email = "test@example.com";
const seedUsers = async (prisma: PrismaClient) => {
const start = Date.now();
console.log("Seeding users...");
const user = await prisma.user.upsert({
where: { email },
update: {},
create: {
email,
name: "Test User",
},
});
const end = Date.now();
console.log(`Seeding users completed in ${end - start}ms`);
return user;
};
export default seedUsers;
main.ts
:
import { PrismaClient } from "@prisma/client";
import seedUsers from "./0_users";
import seedBooks from "./1_books";
const prisma = new PrismaClient();
async function main() {
const start = new Date();
console.log("Seeding database...");
const user = await seedUsers(prisma);
const books = await seedBooks(prisma, user.id);
const end = new Date();
console.log(`Seeding completed: ${end.getTime() - start.getTime()}ms`);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
Step 6: Running Seeds
To run your seeds, you can use a task runner like Make. Here's an example Makefile entry:
prisma-seed-dev:
dotenv -e .env -- npx prisma db seed
Then, you can run make prisma-seed-dev
to execute your seed scripts.
Advanced: Handling Dependencies
For more complex seeding scenarios with dependencies between tables, you can create a simple pipeline using Promises. Here's an example of how you might structure this:
const user = await seedUsers(prisma);
const books = await seedBooks(prisma, user.id);
await Promise.all([
seedX(prisma, user.id, books[0].id).then(async (x) => {
await Promise.all([
seedXX(prisma, user.id, x.id),
seedXXX(prisma, user.id, x.id)
]);
}),
seedY(prisma, books[0].id).then(async (y) => {
await Promise.all([
seedYY(prisma, user.id, y.id),
seedYYY(prisma, user.id, y.id)
]);
})
]);
This approach allows you to handle dependencies between your seed data efficiently.
Conclusion
By using a separate TypeScript configuration for seeding and structuring your seed files carefully, you can create a robust and efficient seeding process for your Next.js and Prisma-based applications. This approach maintains compatibility with Next.js's recommended settings while giving you the flexibility to run TypeScript-based seed scripts.
Remember to adjust the seeding logic based on your specific database schema and requirements. Happy coding!
Top comments (0)