ADR-0008 ORM / camada de queries
Padrão da empresa para acesso à base de dados — Drizzle ORM v1 para queries, Drizzle Kit para migrações.
- Decisão
- Drizzle ORM v1 + Drizzle Kit sobre Bun SQLGuardar e proteger
- Estado
- Aceite
- Data
- Âmbito
- Predefinição da empresa para todas as novas apps
Ligações
Apoia-se em
Contexto
Seção intitulada “Contexto”O Postgres é o nosso motor (ADR-0007). A questão é como o código TypeScript fala com ele. Requisitos:
- Segurança de tipos total — resultados de queries tipados de ponta a ponta, sem ginástica de codegen
- Transparência do SQL — devemos conseguir prever o SQL que uma query produz; sem magia de ORM a surpreender-nos em produção
- Migrações como código — versionadas, revisáveis, executáveis em CI e no momento do deploy
- Funciona em Bun (ADR-0035) com TCP direto ao Postgres (ADR-0003)
- Combina com o Zod (ADR-0005) — os esquemas da base de dados e os esquemas de validação da API não devem divergir
Opções consideradas
Seção intitulada “Opções consideradas”1. Drizzle ORM + Drizzle Kit
Seção intitulada “1. Drizzle ORM + Drizzle Kit”ORM TypeScript SQL-first. Esquemas definidos em TypeScript, camada de queries fina que mapeia diretamente para SQL, Drizzle Kit para migrações/introspeção/studio.
Prós
- SQL-first: as queries leem-se como SQL e produzem SQL previsível — sem surpresas do query planner
- Esquema como TypeScript: sem DSL separada, inferência completa em selects/inserts
- Leve: TS puro, sem passo de codegen, arranque rápido, trivial de correr em Bun e em imagens Docker distroless
- Drizzle Kit: geração de migrações a partir de diferenças de esquema,
migrateno deploy,studiopara navegar drizzle-orm/zod(o pacote separadodrizzle-zodna 0.x) gera esquemas Zod a partir dos esquemas das tabelas — sinergia direta com o ADR-0005 (uma única fonte de verdade, sem divergência)- O Postgres é o dialeto mais bem suportado do Drizzle (ADR-0007)
Contras
- Mais jovem do que o Prisma; ecossistema mais pequeno e menos respostas no Stack Overflow
- A v1 ainda é um release candidate (a linha estável é a 0.45.x); a v1 renomeia os pacotes de validadores e refaz a API de queries relacionais
- A API de queries relacionais tem arestas por limar em casos muito aninhados
- A equipa tem de se sentir à vontade a ler SQL — uma vantagem, mas exige a competência
2. Prisma
Seção intitulada “2. Prisma”O ORM TypeScript incumbente.
Prós
- O maior ecossistema, mais tutoriais, ferramentas maduras (Prisma Studio)
- DSL de esquema amigável; acessível para equipas que começam pelo ORM
Contras
- DSL de esquema separada (
schema.prisma) em vez de TypeScript — passo de codegenprisma generate, tipos que ficam desfasados do esquema até serem regenerados - (O Prisma 7 deixou de usar por predefinição o motor de queries em Rust — compilador de queries em TypeScript mais driver adapters — pelo que o peso no deploy deixou de ser um fator diferenciador)
- Menos transparente quanto ao SQL; as queries geradas podem surpreender à escala
3. Kysely
Seção intitulada “3. Kysely”Query builder de SQL puro e com tipos seguros.
Prós
- Excelente transparência do SQL e inferência de tipos
- Minúsculo, sem dependências, corre em qualquer lado
Contras
- Apenas query builder: sem migrações, sem gestão de esquema — teríamos de montar isso com ferramentas adicionais
- Mais trabalho manual com relações e inserts
4. SQL puro (pg / postgres.js)
Seção intitulada “4. SQL puro (pg / postgres.js)”Prós: zero abstração. Contras: sem tipos a não ser com muito esforço manual, SQL em strings propenso a erros, sem solução de migrações.
Decisão
Seção intitulada “Decisão”Drizzle ORM v1 para queries e definição de esquemas, Drizzle Kit v1 para migrações e ferramentas — a camada de acesso à base de dados padrão da empresa.
Em concreto:
- As novas apps começam na linha v1, mesmo sendo um release candidate — começar na 0.x significaria uma migração garantida (renomeações de pacotes, refação da API de queries relacionais) dentro de meses. Fixar versões exatas (sem
^) enquanto a v1 estiver em pré-lançamento; atualizar de forma deliberada - Driver: o
Bun.SQLintegrado no Bun (ADR-0035), através dedrizzle-orm/bun-sql: um poolnew SQL(env.DATABASE_URL), envolvido pelotraceSqlpara um span por query (ADR-0015), entregue adrizzle({ client }). Sem pacote de driver, sem addon nativo, nada para compilar. O Drizzle só disponibiliza este driver na linha v1, que já usamos. (Alterado em 2026-11-12: este ADR escolheu primeiro opg-native. Alterado em 2026-11-13: depois opg, o cliente JS puro do node-postgres; o cliente integrado do Bun substitui-o.) - Os esquemas das tabelas vivem em TypeScript (
schema.ts) — a única fonte de verdade - As migrações são geradas e aplicadas com o Drizzle Kit (
drizzle-kit generate/migrate), versionadas no repositório e executadas em CI/deploy - Os esquemas Zod para as fronteiras da API são derivados com
drizzle-orm/zodonde as formas se sobrepõem (ADR-0005) - SQL puro através do template
sqldo Drizzle é bem-vindo onde se lê melhor do que o query builder
Os fatores decisivos: a transparência do SQL (podemos sempre ver e controlar o que chega ao Postgres), esquemas nativos em TypeScript sem DSL nem codegen, um ORM leve em TS puro que se encaixa no Bun e no Docker, migrações first-party e a ponte drizzle-orm/zod que evita que os esquemas da base de dados e da API divirjam. Aceitamos o ecossistema mais jovem e o risco de pré-lançamento da v1 em vez de uma migração quase certa de 0.x para v1.
Consequências
Seção intitulada “Consequências”Mais fácil:
- Um único ficheiro TypeScript define as tabelas → tipos, migrações e esquemas Zod derivam dele
- SQL previsível: a otimização de desempenho faz-se em queries que conseguimos ver, não nos internos do ORM
- Bun + Docker + Drizzle = arranque rápido, sem passo de codegen no build
- O Drizzle Studio permite navegar na base de dados sem outra ferramenta
- O driver faz parte do runtime: sem pacote de driver para atualizar, sem compilador nem libpq nos portáteis, no CI ou na imagem
Mais difícil:
- Menos respostas para copiar e colar do que no Prisma; a equipa lê a documentação do Drizzle e SQL, não apenas tutoriais
- É preciso disciplina para manter o uso de
sqlpuro legível e revisto - Correr um release candidate: atualizações de RC para RC podem quebrar, e a maioria dos tutoriais e respostas online ainda mostra a API 0.x. Reavaliar quando a v1 passar a estável
- O
Bun.SQLé mais jovem do que o node-postgres, e o driverbun-sqldo Drizzle existe apenas na linha de release candidate v1 (a rc.4 corrigiu umdb.selectque a rc.3 tinha partido): atualizar o Drizzle e o Bun com os testes de integração a verde (ADR-0014) - Não existe instrumentação OpenTelemetry mantida para o
Bun.SQL, pelo que os spans de queries vêm do nosso wrappertraceSqlaté o próprio Bun fazer o trace das queries (ADR-0015)
Do que abdicamos: da gravidade de ecossistema e do onboarding polido do Prisma, e da maturidade e da instrumentação mantida de queries do node-postgres. Aceite — a transparência do SQL e os esquemas TypeScript sem codegen importam-nos mais do que o volume de tutoriais, e um driver integrado no runtime é uma dependência a menos para manter atualizada.

