From ts-dev-kit
Provides Drizzle ORM reference for PostgreSQL: pgTable schemas with types/indexes/constraints, typesafe queries/joins/relations, drizzle-kit migrations, sql template, and PostGIS/pg_vector extensions.
npx claudepluginhub jgamaraalv/ts-dev-kit --plugin ts-dev-kitThis skill uses the workspace's default tool permissions.
Drizzle is a headless TypeScript ORM. Zero dependencies, SQL-like API, single-query output.
Defines type-safe database schemas, queries, relations, and migrations using Drizzle ORM in TypeScript for PostgreSQL, MySQL, SQLite, Cloudflare D1, and Durable Objects.
Provides Drizzle ORM patterns for schema definition, CRUD operations, relations, queries, transactions, and migrations. Supports PostgreSQL, MySQL, SQLite, MSSQL, CockroachDB.
Provides expertise in Drizzle ORM for TypeScript: schema design, relational queries, Drizzle Kit migrations, and serverless integrations with Neon, Supabase, PlanetScale.
Share bugs, ideas, or general feedback.
Drizzle is a headless TypeScript ORM. Zero dependencies, SQL-like API, single-query output.
Packages: drizzle-orm (runtime), drizzle-kit (CLI/migrations).
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema";
import { relations } from "./relations";
const db = drizzle(process.env.DATABASE_URL, { schema, relations });
Or with existing Pool:
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle({ client: pool, schema, relations });
import {
pgTable,
pgEnum,
serial,
text,
integer,
timestamp,
uuid,
jsonb,
index,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
export const statusEnum = pgEnum("status", ["active", "inactive", "banned"]);
export const users = pgTable(
"users",
{
id: uuid("id")
.default(sql`gen_random_uuid()`)
.primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
status: statusEnum().default("active").notNull(),
metadata: jsonb("metadata").$type<{ roles: string[] }>(),
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
},
(t) => [index("users_email_idx").on(t.email)],
);
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
authorId: uuid("author_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
});
import { defineRelations } from "drizzle-orm";
import * as schema from "./schema";
export const relations = defineRelations(schema, (r) => ({
users: {
posts: r.many.posts({ from: r.users.id, to: r.posts.authorId }),
},
posts: {
author: r.one.users({ from: r.posts.authorId, to: r.users.id }),
},
}));
import { eq, and, ilike, sql } from "drizzle-orm";
// SELECT
const allUsers = await db.select().from(users);
const user = await db.select().from(users).where(eq(users.id, id));
// INSERT
const [created] = await db
.insert(users)
.values({ name: "Dan", email: "dan@example.com" })
.returning();
// UPDATE
await db.update(users).set({ name: "Updated" }).where(eq(users.id, id));
// DELETE
await db.delete(users).where(eq(users.id, id));
// UPSERT
await db
.insert(users)
.values({ id, name: "Dan", email: "dan@ex.com" })
.onConflictDoUpdate({ target: users.id, set: { name: "Dan" } });
// Nested eager loading (single SQL query)
const usersWithPosts = await db.query.users.findMany({
with: { posts: true },
where: { status: "active" },
orderBy: { createdAt: "desc" },
limit: 10,
});
const user = await db.query.users.findFirst({
where: { id: userId },
with: { posts: { columns: { id: true, title: true } } },
});
# drizzle.config.ts -> see references/migrations.md
npx drizzle-kit generate # schema diff -> SQL files
npx drizzle-kit migrate # apply SQL to database
npx drizzle-kit push # direct push (no SQL files)
npx drizzle-kit pull # introspect DB -> Drizzle schema
npx drizzle-kit studio # visual browser UI
const filters: SQL[] = [];
if (name) filters.push(ilike(users.name, `%${name}%`));
if (status) filters.push(eq(users.status, status));
await db
.select()
.from(users)
.where(and(...filters));
await db.transaction(async (tx) => {
const [user] = await tx.insert(users).values({ name: "Dan" }).returning();
await tx.insert(posts).values({ title: "Hello", authorId: user.id });
});
type User = typeof users.$inferSelect;
type NewUser = typeof users.$inferInsert;
<quick_reference>
| Import path | Key exports |
|---|---|
drizzle-orm/pg-core | pgTable, pgEnum, column types (serial, text, integer, uuid, timestamp, jsonb, varchar, boolean, numeric, bigint, geometry, vector, ...), index, uniqueIndex, unique, check, primaryKey, foreignKey |
drizzle-orm | Operators: eq, ne, gt, gte, lt, lte, and, or, not, isNull, isNotNull, inArray, between, like, ilike, exists, sql, asc, desc. Utilities: getColumns, defineRelations, cosineDistance, l2Distance |
drizzle-orm (types) | InferSelectModel, InferInsertModel |
drizzle-zod | createInsertSchema, createSelectSchema |
</quick_reference>
For detailed API coverage, see: