Drizzle ORM
02 / 02

Migrations, Transactions & Serverless Drivers

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 studio

Transactions

// 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