Melhores práticas de Prisma ORM para seniors
Guia técnico para elevar a qualidade, performance e manutenção de aplicações Node.js com Prisma.
1. Arquitetura do Prisma Client e ciclo de vida
- Instância única do PrismaClient: crio uma única instância por aplicação e a reutilizo entre requisições para evitar overhead de reconexões e consumo de recursos. Em ambientes serverless, exponho a instância via global para manter reuso entre invocações.
- Separação entre domínio e persistência: o Prisma schema reflete o modelo de dados persistente, enquanto as regras de negócio residem na camada de domínio (serviços/use-cases). DTOs ajudam a isolar a API dos modelos de dados internos.
- Versionamento de migrations: utilizo Prisma Migrate em pipelines de CI/CD. Mantenho migrations sob controle de versão, evitando alterações manuais diretas no banco. Desenvolvimento com prisma migrate dev; produção com prisma migrate deploy.
- Geração de tipos e produtividade: manter o PrismaClient gerado de forma previsível facilita tipagem estática no TypeScript e reduz erros de compile-time.
2. Consultas eficientes e padrões de modelagem
- Consiga o mínimo necessário: prefira selecionar apenas os campos que serão usados com select, ou traga relações apenas quando necessário com include. Evito fetch de dados desnecessários para reduzir payloads e consumo de memória.
- Combinação inteligente de relações: quando precisar de dados de entidades relacionadas, utilize include com filtragem interna e limites (take) para evitar N+1 e excesso de dados.
- Paginação baseada em cursor: para grandes volumes, use cursor-based pagination com take e orderBy, mantendo a posição entre páginas sem contagens custosas.
- Contagens eficientes: se houver necessidade de contagem, use _count para obter números sem retornar registros completos.
- Indexação relevante: posicione índices com @index e @unique em colunas com alto volume de leitura/filtragem. Pense em padrões de consulta comuns da aplicação ao projetar o schema.
// Exemplo: busca de posts com dados do autor e contagem de comentários
const posts = await prisma.post.findMany({
where: { published: true },
take: 20,
orderBy: { createdAt: 'desc' },
include: {
author: { select: { id: true, name: true } },
comments: { where: { approved: true }, take: 5, select: { id: true } }
},
_count: { select: { comments: true } }
});
3. Transações e consistência de dados
- Transações atômicas: use prisma.$transaction para envolver múltiplas operações que precisam ser atômicas. Em caso de erro, a operação é revertida automaticamente.
- Estratégias de transação: é possível usar o padrão de callback (transaction(async tx) => { … }) ou o modo baseado em array (prisma.$transaction([ … ])) para cenários simples.
- Isolamento: se a base de dados suportar, defina o nível de isolamento desejado (por exemplo, Serializable) para evitar condições de corrida em cenários críticos.
- Tratamento de erros: utilize blocos try/catch para capturar falhas, mantendo logs essenciais e propagando erros de forma consistente para o chamador.
// Exemplo: transferência de saldo entre contas em uma transação
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function transferirSaldo(fromUserId: number, toUserId: number, amount: number) {
await prisma.$transaction(async (tx) => {
const from = await tx.account.findUnique({ where: { userId: fromUserId }, select: { balance: true } });
if (!from || from.balance < amount) throw new Error('Saldo insuficiente');
await tx.account.update({ where: { userId: fromUserId }, data: { balance: { decrement: amount } } });
await tx.account.update({ where: { userId: toUserId }, data: { balance: { increment: amount } } });
}, { isolationLevel: 'Serializable' });
}
// Chamada de exemplo
// transferirSaldo(1, 2, 100).catch(err => console.error(err));
4. Modelagem de dados, migrações e observabilidade
- Modelagem clara: use enums para campos com valores restritos, defina relações nomeadas e evite chaves compostas sem necessidade.
- Indices e unicidade: aplique @index e @unique nos campos mais filtrados para melhorar desempenho de queries comuns.
- Auditoria e soft delete: inclua campos como deletedAt ou criadoPor para rastrear alterações sem perder histórico; use filtros explícitos para excluir itens deletados quando necessário.
- Seeds e reprodutibilidade: utilize prisma db seed para datasets iniciais em dev e staging, mantendo scripts versionados.
- Observabilidade: adicione middleware simples para log de queries e métricas de tempo de resposta sem depender de ferramentas externas. Isso ajuda a identificar gargalos sem atrapalhar o fluxo de desenvolvimento.
// Exemplo de schema.prisma (trecho ilustrativo)
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())
updatedAt DateTime @updatedAt
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId, published])
}
Bloco de código relevante
Exemplo de consulta com contagem e paginação baseada em cursor, mantendo o desempenho para listas longas.
// Exemplo de paginação baseada em cursor com contagem de itens de cada item
async function buscarUsuariosPaginados(prisma: PrismaClient, lastId?: number, limit = 20) {
const users = await prisma.user.findMany({
take: limit,
...(lastId ? { cursor: { id: lastId }, skip: 1 } : {}),
orderBy: { id: 'asc' },
select: {
id: true, email: true, name: true,
_count: { select: { posts: true } } // contagem de posts por usuário
}
});
return users;
}
Gostou deste guia técnico?
Confira outros posts da série Prisma ORM para seniors, com foco prático, arquitetura, performance e manutenção.
Sou Apaixonado pela programação e estou trilhando o caminho de ter cada diz mais conhecimento e trazer toda minha experiência vinda do Design para a programação resultando em layouts incríveis e idéias inovadoras! Conecte-se Comigo!