A Next.js app backed by a real SQLite database (upgradeable to PostgreSQL), with Prisma models for users and posts, full CRUD API routes, and type-safe queries throughout.
A Next.js app backed by a real SQLite database (upgradeable to PostgreSQL), with Prisma models for users and posts, full CRUD API routes, and type-safe queries throughout.
Prisma is the TypeScript-first ORM. You define your database schema in a .prisma file, run migrations, and Prisma generates a fully typed client. You get autocomplete on every query.
# Install Prisma npm install prisma @prisma/client npx prisma init --datasource-provider sqlite # Creates: prisma/schema.prisma and .env
generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" url = env("DATABASE_URL") } model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] createdAt DateTime @default(now()) } model Post { id Int @id @default(autoincrement()) title String content String? published Boolean @default(false) author User @relation(fields: [authorId], references: [id]) authorId Int createdAt DateTime @default(now()) }
# Run migration (creates the database tables) npx prisma migrate dev --name init # View your DB in the browser npx prisma studio
In Next.js dev mode, hot reloading creates new Prisma connections on every reload. This exhausts your connection pool. Use a singleton pattern to reuse the client.
import { PrismaClient } from '@prisma/client' const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined } export const prisma = globalForPrisma.prisma ?? new PrismaClient() if (process.env.NODE_ENV !== 'production') { globalForPrisma.prisma = prisma }
Import this singleton everywhere instead of creating new PrismaClient() directly.
Prisma's query API is intuitive and fully typed. Every model gets findMany, findUnique, create, update, delete, and more.
import { prisma } from '@/lib/prisma' import { NextResponse } from 'next/server' export async function GET() { const posts = await prisma.post.findMany({ where: { published: true }, include: { author: { select: { name: true } } }, orderBy: { createdAt: 'desc' }, take: 10 }) return NextResponse.json(posts) } export async function POST(request: Request) { const { title, content, authorId } = await request.json() const post = await prisma.post.create({ data: { title, content, authorId, published: false }, include: { author: true } }) return NextResponse.json(post, { status: 201 }) }
A seed script populates your database with test data. Essential for development and for running tests in CI.
import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() async function main() { const user = await prisma.user.upsert({ where: { email: '[email protected]' }, update: {}, create: { email: '[email protected]', name: 'Demo User' } }) await prisma.post.createMany({ data: [ { title: 'Hello World', content: 'First post!', published: true, authorId: user.id }, { title: 'Getting Started', content: 'Second post', published: true, authorId: user.id }, ] }) console.log('Seeded!') } main().catch(console.error).finally(() => prisma.$disconnect())
{
"prisma": {
"seed": "ts-node prisma/seed.ts"
}
}
// Run with: npx prisma db seed
Day 4 is ready when you are.
Want live instruction and hands-on projects? Join the AI bootcamp — 3 days, 5 cities.
The foundations from today carry directly into Day 4. In the next session the focus shifts to Day 4 — building directly on everything covered here.
Before moving on, verify you can answer these without looking:
Live Bootcamp
Learn this in person — 2 days, 5 cities
Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.
Reserve Your Seat →