Pular para o conteúdo

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

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

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, migrate no deploy, studio para navegar
  • drizzle-orm/zod (o pacote separado drizzle-zod na 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

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 codegen prisma 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

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

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.

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.SQL integrado no Bun (ADR-0035), através de drizzle-orm/bun-sql: um pool new SQL(env.DATABASE_URL), envolvido pelo traceSql para um span por query (ADR-0015), entregue a drizzle({ 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 o pg-native. Alterado em 2026-11-13: depois o pg, 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/zod onde as formas se sobrepõem (ADR-0005)
  • SQL puro através do template sql do 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.

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 sql puro 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 driver bun-sql do Drizzle existe apenas na linha de release candidate v1 (a rc.4 corrigiu um db.select que 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 wrapper traceSql até 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.