drizzle-orm

Drizzle ORM — type-safe, lightweight TypeScript ORM for SQL databases. Schema declaration, CRUD queries, joins, relations, migrations with Drizzle Kit, and database seeding. Use when defining database schemas, writing queries (select/insert/update/delete), setting up migrations, configuring drizzle.config.ts, establishing database connections, validating data with drizzle-zod/valibot, or working with PostgreSQL, MySQL, SQLite, Turso, Bun SQL, Neon, Supabase, PGlite, Expo SQLite, Cloudflare D1, PlanetScale, SingleStore, MSSQL, CockroachDB.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "drizzle-orm" with this command: npx skills add fellipeutaka/leon/fellipeutaka-leon-drizzle-orm

Drizzle ORM

~7.4kb minified+gzipped, zero dependencies, serverless-ready.

Quick Start

Install

# PostgreSQL
npm i drizzle-orm pg
npm i -D drizzle-kit @types/pg

# MySQL
npm i drizzle-orm mysql2
npm i -D drizzle-kit

# SQLite
npm i drizzle-orm better-sqlite3
npm i -D drizzle-kit @types/better-sqlite3

# Turso / LibSQL
npm i drizzle-orm @libsql/client
npm i -D drizzle-kit

# Bun SQL (PostgreSQL — zero extra deps)
bun add drizzle-orm
bun add -D drizzle-kit

# Bun SQLite (zero extra deps, sync APIs)
bun add drizzle-orm
bun add -D drizzle-kit

Config

// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql", // "postgresql" | "mysql" | "sqlite" | "turso" | "singlestore"
  schema: "./src/db/schema.ts",
  out: "./drizzle",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

Schema

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

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

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

Connect & Query

import { drizzle } from "drizzle-orm/node-postgres";
import { eq } from "drizzle-orm";
import * as schema from "./schema";

const db = drizzle(process.env.DATABASE_URL!, { schema });

// select
const allUsers = await db.select().from(schema.users);

// insert
const [user] = await db.insert(schema.users)
  .values({ name: "Dan", email: "dan@example.com" })
  .returning();

// update
await db.update(schema.users)
  .set({ name: "Daniel" })
  .where(eq(schema.users.id, 1));

// delete
await db.delete(schema.users).where(eq(schema.users.id, 1));

See references/connections.md for all provider setups (Neon, Turso, Supabase, D1, etc.).

Schema Declaration

Import table/column builders from the dialect-specific module:

// PG:     import { pgTable, serial, text, ... } from "drizzle-orm/pg-core";
// MySQL:  import { mysqlTable, int, varchar, ... } from "drizzle-orm/mysql-core";
// SQLite: import { sqliteTable, integer, text, ... } from "drizzle-orm/sqlite-core";

Common Column Types (PG)

TypeUsageNotes
serial()Auto-increment PKUse integer().generatedAlwaysAsIdentity() for new projects
integer()4-byte int
bigint({ mode: "number" })8-byte int"bigint" mode for >2^53
text()Unlimited text{ enum: [...] } for TS union
varchar({ length: n })Variable-length
boolean()true/false
timestamp()Date/time{ withTimezone: true }, mode: "date"
date()Calendar datemode: "date" for JS Date
json() / jsonb()JSON data.$type<T>() for typing
uuid()UUID.defaultRandom() for gen_random_uuid()
numeric({ precision, scale })Exact decimalReturns string by default

Constraint Modifiers

column.notNull()
column.default(value)
column.default(sql`now()`)
column.$defaultFn(() => createId())   // runtime default
column.$onUpdate(() => new Date())    // runtime on update
column.primaryKey()
column.unique()
column.references(() => other.id, { onDelete: "cascade" })
column.$type<CustomType>()            // branded types

Auto-map Casing

// drizzle.config.ts
export default defineConfig({
  casing: "snake_case", // camelCase TS keys -> snake_case DB columns
});

Full column type catalogs: PG | MySQL | SQLite | MSSQL/CockroachDB/SingleStore

CRUD Operations

All operators imported from "drizzle-orm":

import { eq, ne, gt, gte, lt, lte, and, or, not, like, ilike, inArray, between, isNull, sql } from "drizzle-orm";

Select

// basic
await db.select().from(users);

// partial + where
await db.select({ id: users.id, name: users.name })
  .from(users)
  .where(and(eq(users.role, "admin"), gt(users.age, 18)))
  .orderBy(asc(users.name))
  .limit(10).offset(20);

// aggregation
await db.select({ role: users.role, count: sql<number>`count(*)` })
  .from(users).groupBy(users.role).having(gt(sql`count(*)`, 5));

Insert

// single + returning
const [user] = await db.insert(users).values({ name: "Dan" }).returning();

// bulk
await db.insert(users).values([{ name: "A" }, { name: "B" }]);

// upsert (PG/SQLite)
await db.insert(users).values({ id: 1, name: "Dan" })
  .onConflictDoUpdate({ target: users.id, set: { name: "Dan" } });

// upsert (MySQL)
await db.insert(users).values({ id: 1, name: "Dan" })
  .onDuplicateKeyUpdate({ set: { name: "Dan" } });

Update / Delete

await db.update(users).set({ name: "Jane" }).where(eq(users.id, 1)).returning();
await db.delete(users).where(eq(users.id, 1)).returning();

Full queries reference: references/queries.md

Joins

// inner join
await db.select().from(users)
  .innerJoin(posts, eq(users.id, posts.authorId));

// left join
await db.select().from(users)
  .leftJoin(orders, eq(users.id, orders.userId));

// self-join with alias
import { alias } from "drizzle-orm/pg-core";
const parent = alias(users, "parent");
await db.select().from(users).leftJoin(parent, eq(users.managerId, parent.id));

Relations

V1 (Stable)

import { relations } from "drizzle-orm";

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));

Relational Queries

Pass schema to drizzle to enable db.query:

const db = drizzle(url, { schema });

const result = await db.query.users.findMany({
  columns: { id: true, name: true },
  with: { posts: { with: { comments: true } } },
  where: (users, { eq }) => eq(users.id, 1),
  orderBy: (users, { desc }) => desc(users.createdAt),
  limit: 10,
});

const user = await db.query.users.findFirst({
  where: (users, { eq }) => eq(users.name, "Dan"),
  with: { posts: true },
});

V2 (Beta)

import { defineRelations } from "drizzle-orm";

export const relations = defineRelations(schema, (r) => ({
  users: { posts: r.many.posts() },
  posts: { author: r.one.users({ from: r.posts.authorId, to: r.users.id }) },
}));

V2 adds .through() for many-to-many without junction table boilerplate.

Full relations reference: references/relations.md

Drizzle Kit

CommandDescription
npx drizzle-kit generateCreate SQL migration files from schema diff
npx drizzle-kit migrateApply pending migrations
npx drizzle-kit pushSync schema directly (prototyping only)
npx drizzle-kit pullIntrospect DB → Drizzle schema
npx drizzle-kit checkValidate migration consistency
npx drizzle-kit studioVisual database browser

Full migrations reference: references/migrations.md

Transactions

const result = await db.transaction(async (tx) => {
  const [user] = await tx.insert(users).values({ name: "Dan" }).returning();
  await tx.insert(accounts).values({ userId: user.id, balance: 0 });
  return user;
});

Rollback with tx.rollback(). Nested transactions create savepoints.

Full reference: references/transactions-and-batch.md

Raw SQL

import { sql } from "drizzle-orm";

// typed expression
const lower = sql<string>`lower(${users.name})`;

// full raw query
await db.execute(sql`SELECT * FROM ${users} WHERE ${users.id} = ${id}`);

// placeholder for prepared statements
const prepared = db.select().from(users)
  .where(eq(users.id, sql.placeholder("id")))
  .prepare("get_user");
await prepared.execute({ id: 1 });

Reference Index

TopicFile
PostgreSQL column types, enums, schemas, indexes, views, RLSreferences/schema-postgresql.md
MySQL column types, enums, indexes, viewsreferences/schema-mysql.md
SQLite column types, indexes, viewsreferences/schema-sqlite.md
MSSQL, CockroachDB, SingleStore typesreferences/column-types-minor-dialects.md
Full query operators, advanced select, joins, CTEs, set ops, $countreferences/queries.md
Relations v1 + v2, relational queries APIreferences/relations.md
Drizzle Kit config, commands, programmatic migrationreferences/migrations.md
Transactions, savepoints, batch APIreferences/transactions-and-batch.md
drizzle-zod, drizzle-valibot, drizzle-typebox, etc.references/schema-validation.md
Connection setup per provider (Neon, Turso, Supabase, D1, PGlite, Expo, etc.)references/connections.md
Database seeding with drizzle-seed, versioningreferences/drizzle-seed.md
Read replicas, custom types, caching, ESLint, gotchas, drizzle-graphqlreferences/advanced-patterns.md

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

docker

No summary provided by upstream source.

Repository SourceNeeds Review
General

commit-work

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

clean-code

No summary provided by upstream source.

Repository SourceNeeds Review