KeiSeiKit-1.0/_blocks/db-drizzle.md
Parfii-bot f884891862 feat(blocks): 5 database blocks — postgres/sqlite/sqlx/drizzle/migration-hygiene
- db-postgres.md: PG17 patterns (indexes, pooling, backup); [E4]
- db-sqlite.md: WAL prod patterns, Turso/LiteFS/D1, FTS5
- db-sqlx.md: Rust compile-time checked queries, offline mode
- db-drizzle.md: TS schema-first, drizzle-kit migrations
- db-migration-hygiene.md: universal up/down, zero-downtime,
  backfill, checksum tracking

All blocks <60 LOC per Constructor Pattern. Version numbers
marked [UNVERIFIED] where exact minor pins are needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:31:37 +08:00

2.3 KiB

DB — Drizzle ORM (TypeScript) patterns

Use when the project is TypeScript/Next.js/Bun/Node and needs a type-safe SQL layer without Prisma's heavyweight engine process. Pairs with stack-nextjs. [E4 — expert assessment]

Core versions: drizzle-orm (latest on npm) + drizzle-kit (migrations CLI) as of 2026-04. Peer-deps: pg for Postgres, better-sqlite3 / @libsql/client for SQLite, mysql2 for MySQL. [UNVERIFIED: pin exact versions from npm before shipping]

Schema-first, not code-first:

// db/schema.ts
import { pgTable, serial, text, timestamp, integer } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  email: text("email").notNull().unique(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});

export const posts = pgTable("posts", {
  id: serial("id").primaryKey(),
  authorId: integer("author_id").references(() => users.id).notNull(),
  body: text("body").notNull(),
});

schema.ts IS the source of truth. All types flow from it — typeof users.$inferSelect gives you the row type.

Query with full inference:

import { eq } from "drizzle-orm";
const rows = await db.select().from(users).where(eq(users.id, 1));
// rows: { id: number; email: string; createdAt: Date }[]

No codegen step, no separate .prisma file. Type errors surface in the IDE immediately.

Migrations via drizzle-kit:

drizzle-kit generate     # diff schema.ts against prev snapshot → emit SQL in drizzle/
drizzle-kit migrate      # apply pending migrations
drizzle-kit studio       # local web UI to inspect data

Config in drizzle.config.ts — specify dialect, schema, out, dbCredentials.

Connection / pool:

import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 20 });
export const db = drizzle(pool, { schema });

Serverless (Vercel / CF Workers): use neon-serverless or @libsql/client driver instead — the pg Pool doesn't survive cold-start boundaries.

Forbidden: template-string SQL with untrusted input (sql\SELECT * WHERE x = ${userInput}`— usesql.placeholderor the query builder); committingdrizzle/meta/_journal.json` conflicts (merge manually or regenerate); mixing drizzle-kit versions across dev machines.