Drizzle ORM: Migrations, Transactions & Serverless Drivers
drizzle-kit: Migrations & Studio
# drizzle-kit is a separate dev-time CLI, not a runtime dependency
# drizzle-orm is the lightweight library your app actually ships
# Generates a plain, reviewable SQL migration file -- diffs your
# TypeScript schema against the tracked migration history
npx drizzle-kit generate
# Apply generated migrations in order
npx drizzle-kit migrate
# Fast local iteration: sync schema directly, no migration file --
# convenient for early dev, generally NOT used for production
npx drizzle-kit push
# Local browser GUI for inspecting actual data against the schema
npx drizzle-kit studioTransactions
// All queries against tx succeed and commit together, or a thrown
// error rolls everything back -- atomicity for multi-step operations
await db.transaction(async (tx) => {
await tx.update(accounts).set({ balance: sql`balance - 100` }).where(eq(accounts.id, fromId));
await tx.update(accounts).set({ balance: sql`balance + 100` }).where(eq(accounts.id, toId));
});
// Prepared statements -- parse/plan once, execute many times with
// different bound values (hot-path queries with varying inputs)
import { placeholder } from 'drizzle-orm';
const getUserById = db
.select()
.from(users)
.where(eq(users.id, placeholder('id')))
.prepare();
const user = await getUserById.execute({ id: someUserId });Serverless/Edge Drivers
// Serverless/edge functions often can't hold a persistent TCP pool --
// providers offer HTTP-based connectivity instead. Drizzle ships
// dialect-specific adapters so the SAME query builder syntax works.
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!);
const db = drizzle(sql);
// Same query API regardless of underlying connection mechanism
const allUsers = await db.select().from(users);Zod Integration & Drizzle vs Prisma
import { createInsertSchema } from 'drizzle-zod';
// Validation schema derived from the ACTUAL table definition --
// stays consistent automatically, no hand-written schema to drift
const insertUserSchema = createInsertSchema(users);
const parsed = insertUserSchema.parse(requestBody);Drizzle: schema IS TypeScript, no codegen step, thinner runtime, SQL-close syntax -- more direct control, less abstraction.
Prisma: separate .prisma DSL compiled via a generate step into a client -- more opinionated conveniences, larger ecosystem.
Neither is objectively better -- the choice is how much abstraction/magic a team wants versus direct SQL control.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free