Drizzle orm
Skill ComeOnOliver/skillshub/skills/TerminalSkills/skills/drizzle-orm
π§ The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.
npx -y skills add ComeOnOliver/skillshub --skill drizzle-ormAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
4.7 KB, as published. Nobody here has run it
Drizzle ORM β TypeScript SQL That Feels Like SQL
You are an expert in Drizzle ORM, the lightweight TypeScript ORM that maps directly to SQL. You help developers write type-safe database queries that look like SQL (not a new query language), generate migrations from schema changes, and deploy to serverless environments with zero overhead β supporting Postgres, MySQL, SQLite, Turso, Neon, PlanetScale, and Cloudflare D1.
Core Capabilities
Schema Definition
// db/schema.ts
import { pgTable, text, integer, boolean, timestamp, serial, uuid, varchar, jsonb, index, uniqueIndex } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
name: varchar("name", { length: 255 }).notNull(),
email: varchar("email", { length: 255 }).notNull(),
role: varchar("role", { length: 20 }).notNull().default("user"),
metadata: jsonb("metadata").$type<{ plan: string; seats: number }>(),
createdAt: timestamp("created_at").defaultNow().notNull(),
}, (table) => ({
emailIdx: uniqueIndex("email_idx").on(table.email),
}));
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 500 }).notNull(),
content: text("content"),
published: boolean("published").default(false).notNull(),
authorId: uuid("author_id").references(() => users.id).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
}, (table) => ({
authorIdx: index("author_idx").on(table.authorId),
publishedIdx: index("published_idx").on(table.published, table.createdAt),
}));
// Relations (for query builder)
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
Queries
import { drizzle } from "drizzle-orm/node-postgres";
import { eq, and, gte, desc, sql, like, count } from "drizzle-orm";
import * as schema from "./schema";
const db = drizzle(pool, { schema });
// Select β reads like SQL
const publishedPosts = await db.select()
.from(posts)
.where(and(
eq(posts.published, true),
gte(posts.createdAt, new Date("2026-01-01")),
))
.orderBy(desc(posts.createdAt))
.limit(20);
// Join
const postsWithAuthors = await db.select({
title: posts.title,
authorName: users.name,
authorEmail: users.email,
})
.from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true));
// Relational queries (Prisma-like)
const usersWithPosts = await db.query.users.findMany({
with: { posts: { where: eq(posts.published, true), limit: 5 } },
where: eq(users.role, "admin"),
});
// Insert
const [newUser] = await db.insert(users)
.values({ name: "Alice", email: "[email protected]" })
.returning();
// Upsert
await db.insert(users)
.values({ id: userId, name: "Alice", email: "[email protected]" })
.onConflictDoUpdate({ target: users.email, set: { name: "Alice Updated" } });
// Aggregate
const [stats] = await db.select({
total: count(),
published: count(sql`CASE WHEN ${posts.published} THEN 1 END`),
}).from(posts);
// Transaction
await db.transaction(async (tx) => {
const [post] = await tx.insert(posts).values({ title: "New", authorId: userId }).returning();
await tx.insert(notifications).values({ userId, message: `Post ${post.id} created` });
});
Migrations
npx drizzle-kit generate # Generate migration from schema diff
npx drizzle-kit push # Push schema directly (prototyping)
npx drizzle-kit migrate # Apply migrations
npx drizzle-kit studio # Visual data browser
Installation
npm install drizzle-orm
npm install -D drizzle-kit
# + driver: pg | mysql2 | better-sqlite3 | @libsql/client | @neondatabase/serverless
Best Practices
- SQL-like syntax β Drizzle queries map 1:1 to SQL; if you know SQL, you know Drizzle
- Zero overhead β No query engine at runtime; generates SQL strings directly; serverless-friendly
- Schema as code β TypeScript schema = migration source;
drizzle-kit generatediffs and creates SQL - Relational queries β Use
db.queryfor Prisma-like nested includes;db.selectfor raw SQL control - Serverless drivers β Use
@neondatabase/serverless,@libsql/client, D1 for edge/serverless - Indexes β Define in table callback; Drizzle generates CREATE INDEX in migrations
- Type inference β
typeof users.$inferSelectand$inferInsertfor row types; no manual type definitions - Prepared statements β Use
.prepare()for repeated queries; avoids re-parsing on every call