Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
npm install prisma @prisma/client
npx prisma init// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
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())
}npx prisma migrate dev --name init
npx prisma generate// lib/prisma.ts
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;Quando usar isso: Você precisa de consultas de banco de dados com segurança de tipos em um aplicativo Next.js com tipos gerados automaticamente, manipulação de relações e migrações de esquema.
// app/posts/page.tsx (Server Component)
import { prisma } from "@/lib/prisma";
export default async function PostsPage() {
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: { select: { name: true, email: true } } },
orderBy: { createdAt: "desc" },
take: 20,
});
return (
<div className="max-w-3xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Publicações Publicadas</h1>
{posts.map((post) => (
<article key={post.id} className="border-b py-4">
<h2 className="text-xl font-semibold">{post.title}</h2>
<p className="text-gray-600 text-sm">
por {post.author.name ?? "Anônimo"}
</p>
{post.content && <p className="mt-2">{post.content}</p>}
</article>
))}
</div>
);
}// app/posts/actions.ts
"use server";
import { prisma } from "@/lib/prisma";
import { revalidatePath } from "next/cache";
export async function createPost(formData: FormData) {
const title = formData.get("title") as string;
const content = formData.get("content") as string;
const authorId = Number(formData.get("authorId"));
await prisma.post.create({
data: { title, content, authorId, published: false },
});
revalidatePath("/posts");
}
export async function publishPost(postId: number) {
await prisma.post.update({
where: { id: postId },
data: { published: true },
});
revalidatePath("/posts");
}
export async function deletePost(postId: number) {
await prisma.post.delete({ where: { id: postId } });
revalidatePath("/posts");
}// app/posts/new/page.tsx
"use client";
import { createPost } from "../actions";
export default function NewPostPage() {
return (
<form action={createPost} className="max-w-md mx-auto p-6 space-y-4">
<input type="hidden" name="authorId" value="1" />
<div>
<label className="block text-sm font-medium">Título</label>
<input
name="title"
required
className="w-full border rounded px-3 py-2"
/>
</div>
<div>
<label className="block text-sm font-medium">Conteúdo</label>
<textarea
name="content"
rows={5}
className="w-full border rounded px-3 py-2"
/>
</div>
<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded"
>
Criar Publicação
</button>
</form>
);
}O que isso demonstra:
revalidatePathschema.prisma, fornecendo campos de modelo autocompletados, travessia de relações e filtros de consulta.node_modules/.prisma/client e é regenerado em prisma generate ou prisma migrate dev.include e select controlam quais dados relacionados são buscados.prisma/migrations/, rastreados por uma tabela _prisma_migrations em seu banco de dados.globalForPrisma) impede que a recarga a quente do Next.js crie novas instâncias PrismaClient, o que esgotaria as conexões do banco de dados.Filtragem e paginação:
const results = await prisma.post.findMany({
where: {
AND: [
{ published: true },
{ title: { contains: searchQuery, mode: "insensitive" } },
],
},
skip: (page - 1) * pageSize,
take: pageSize,
orderBy: { createdAt: "desc" },
});
const total = await prisma.post.count({
where: { published: true },
});Transações:
const [post, user] = await prisma.$transaction([
prisma.post.create({ data: { title: "Olá", authorId: 1 } }),
prisma.user.update({
where: { id: 1 },
data: { name: "Nome Atualizado" },
}),
]);
// Transação interativa
await prisma.$transaction(async (tx) => {
const user = await tx.user.findUnique({ where: { id: 1 } });
if (!user) throw new Error("Usuário não encontrado");
await tx.post.create({ data: { title: "Olá", authorId: user.id } });
});Upsert (criar ou atualizar):
const user = await prisma.user.upsert({
where: { email: "alice@example.com" },
update: { name: "Alice Atualizada" },
create: { email: "alice@example.com", name: "Alice" },
});SQL Bruto para consultas complexas:
const results = await prisma.$queryRaw<
{ id: number; title: string }[]
>`SELECT id, title FROM "Post" WHERE "published" = true LIMIT ${limit}`;User, Post, etc.include e select - nenhuma definição de tipo manual é necessária.Prisma.PostCreateInput para tipos de dados de criação, Prisma.PostWhereInput para filtros.Prisma.PostGetPayload<{ include: { author: true } }> fornece o tipo de retorno exato para uma consulta com inclusões.import { Prisma } from "@prisma/client";
type PostWithAuthor = Prisma.PostGetPayload<{
include: { author: true };
}>;
function renderPost(post: PostWithAuthor) {
return `${post.title} por ${post.author.name}`;
}Esgotamento de conexões em desenvolvimento - A recarga a quente do Next.js cria novas instâncias PrismaClient. Correção: Use o padrão singleton mostrado na seção Receita. Armazene o cliente em globalThis.
Cliente gerado desatualizado - Após alterar schema.prisma, as consultas podem não refletir novos campos. Correção: Execute npx prisma generate após as alterações de esquema. prisma migrate dev faz isso automaticamente.
Consultas N+1 - Acessar relações em um loop sem include dispara uma consulta por iteração. Correção: Use include ou select para carregar antecipadamente as relações na consulta inicial.
Serialização BigInt - Campos BigInt não podem ser serializados para JSON para client components. Correção: Converta BigInt para Number ou String antes de passar para client components: Number(post.viewCount).
Alterações de Enum exigem migração - Adicionar valores a um enum do Prisma requer uma migração, não apenas prisma generate. Correção: Execute npx prisma migrate dev --name add-enum-value.
Confusão de fuso horário DateTime - O Prisma armazena DateTime como UTC. Correção: Sempre manipule a conversão de fuso horário no lado do cliente, não nas consultas.
| Biblioteca | Ideal para | Contrapartida |
|---|---|---|
| Prisma | ORM com segurança de tipos e migrações | Runtime mais pesado, cliente gerado |
| Drizzle ORM | Sintaxe leve, semelhante a SQL | Menos abstração, migrações manuais |
| Kysely | Construtor de consultas com segurança de tipos | Sem gerenciamento de esquema ou migrações |
| TypeORM | ORM baseado em decoradores | Menos segurança de tipos, mais pesado |
| Knex.js | Construtor de consultas SQL bruto | Sem geração de tipos, tipos manuais |
PrismaClient, abrindo novas conexões de banco de dados.globalThis garante que apenas uma instância persista entre as recargas a quente.include busca todos os campos escalares no modelo pai mais as relações especificadas.select busca apenas os campos que você lista explicitamente, incluindo relações.include e select no mesmo nível superior.select quando quiser minimizar os dados retornados.import { prisma } from "@/lib/prisma";
export default async function Page() {
const users = await prisma.user.findMany();
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}Nenhuma camada de API é necessária - Server Components são executados no servidor e podem consultar o banco de dados diretamente.
prisma.$transaction([query1, query2]) executa as consultas em ordem.prisma.$transaction(async (tx) => { ... }) permite que você use resultados intermediários.node_modules/.prisma/client.schema.prisma não regenera o cliente.npx prisma generate após cada alteração de esquema.npx prisma migrate dev executa generate automaticamente.const page = 2;
const pageSize = 10;
const [posts, total] = await Promise.all([
prisma.post.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
orderBy: { createdAt: "desc" },
}),
prisma.post.count(),
]);BigInt não podem ser serializados para JSON.Number ou String antes de passar: Number(post.viewCount).Number.MAX_SAFE_INTEGER, use String() em vez disso.import { Prisma } from "@prisma/client";
type PostWithAuthor = Prisma.PostGetPayload<{
include: { author: true };
}>;Prisma.PostGetPayload infere a forma exata com base em include/select.import { Prisma } from "@prisma/client";
const data: Prisma.PostCreateInput = {
title: "Olá",
author: { connect: { id: 1 } },
};*CreateInput, *UpdateInput, *WhereInput e *OrderByInput para cada modelo.migrate dev cria um arquivo de migração SQL, o aplica e regenera o cliente.db push aplica alterações de esquema diretamente sem criar arquivos de migração.migrate dev para fluxos de trabalho de produção onde você precisa de histórico de migração.db push para prototipagem rápida ou quando você não precisa de um rastro de migração.const results = await prisma.$queryRaw<
{ id: number; title: string }[]
>`SELECT id, title FROM "Post" WHERE published = true`;post.author em um loop sem include dispara uma consulta por publicação.include: { author: true } no findMany inicial para carregar antecipadamente as relações.select para buscar apenas os campos específicos do autor que você precisa.Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥