From playground to production
In a real project the schema evolves through migrations, one client instance is shared across the app, and queries live in a data layer your routes call.
The workflow
npx prisma migrate dev --name add-stock # dev: create + apply a migration, regenerate client npx prisma migrate deploy # CI/production: apply pending migrations only npx prisma db seed # run prisma/seed.ts npx prisma generate # regenerate the client after schema changes npx prisma studio # browse data
// lib/db.ts — one client, even with Next.js hot reload
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
// app/menu/page.tsx — a Server Component queries directly
export default async function Menu() {
const dishes = await prisma.dish.findMany({ orderBy: { name: "asc" } });
return <ul>{dishes.map((d) => <li key={d.id}>{d.name}</li>)}</ul>;
}
// NestJS — a PrismaService injected into services
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() { await this.$connect(); }
}Return only what the page needs (select) — never send password hashes or internal fields to the client.