com um clique
drizzle-orm
Drizzle ORM type-safe SQL queries, schema definition, migrations, and Supabase/Postgres integration. Triggers on: drizzle-orm, drizzle, pgTable, mysqlTable, eq(), and(), drizzle migrate, drizzle-kit, schema.ts drizzle.
Menu
Drizzle ORM type-safe SQL queries, schema definition, migrations, and Supabase/Postgres integration. Triggers on: drizzle-orm, drizzle, pgTable, mysqlTable, eq(), and(), drizzle migrate, drizzle-kit, schema.ts drizzle.
Build Raycast extensions using the Raycast API: commands, list views, forms, and preferences. Triggers on: Raycast, @raycast/api, raycast extension, raycast command, showToast, List.Item, Action.
Use Nix and NixOS for fully reproducible development environments, CI pipelines, and deployments. Covers flake-based project setup, devShells, Nix overlays, home-manager, NixOS configuration, and building Docker images with Nix for bit-reproducible containers.
Build, maintain, generate fake test data for, and distribute the Example Workplace Attendance Tracker Excel/VBA tool. Use when asked about the attendance tracker, generating fake workplace data, fixing tracker issues, or creating center-specific templates.
Atlantis — automated Terraform/OpenTofu pull request workflow with plan and apply via PR comments. Use this skill whenever the user needs to automate Terraform plan/apply on PRs, enforce code review before infrastructure changes, set up GitOps for infrastructure, configure Atlantis server with repo-level workflow overrides, or prevent unapproved Terraform applies. Trigger for "atlantis terraform", "atlantis plan", "atlantis apply", "terraform pr automation", "infrastructure gitops atlantis", or "terraform code review workflow".
HashiCorp Boundary — identity-based secure remote access without VPN or bastion hosts. Use this skill whenever the user needs to provide SSH/RDP/database access to engineers without exposing infrastructure, replace bastion hosts with identity-aware access, set up just-in-time access with Vault-brokered credentials, configure Boundary targets and host catalogs, or integrate with SSO for infrastructure access. Trigger for "boundary access", "hashicorp boundary", "replace bastion host", "just-in-time access", "boundary targets", or "identity-based ssh access".
HashiCorp Vault — secrets management, encryption as a service, and dynamic credentials. Use this skill whenever the user needs to store and retrieve secrets, generate dynamic database credentials, issue short-lived certificates (PKI), set up Kubernetes auth for pod secret access, configure Vault policies, or implement secrets rotation. Trigger for "vault secrets", "vault kv", "vault dynamic credentials", "vault pki", "vault kubernetes auth", "hashicorp vault", or "secrets management vault".
| name | drizzle-orm |
| description | Drizzle ORM type-safe SQL queries, schema definition, migrations, and Supabase/Postgres integration. Triggers on: drizzle-orm, drizzle, pgTable, mysqlTable, eq(), and(), drizzle migrate, drizzle-kit, schema.ts drizzle. |
Use when you need type-safe SQL with full TypeScript inference, want explicit control over queries (no magic), or are integrating with Supabase Postgres.
drizzle-kit for migrations — never write raw SQL migration files by hand.returning() after insert/update to get the full row back.select({ col: table.col }) for partial selects over fetching full rowsnpm install drizzle-orm postgres
npm install -D drizzle-kit
// src/db/schema.ts
import {
pgTable, serial, text, varchar, integer, boolean,
timestamp, uuid, index, uniqueIndex, foreignKey,
} from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable(
'users',
{
id: uuid('id').defaultRandom().primaryKey(),
email: varchar('email', { length: 255 }).notNull().unique(),
name: text('name').notNull(),
role: text('role', { enum: ['admin', 'user', 'viewer'] }).default('user').notNull(),
active: boolean('active').default(true).notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
},
(table) => ({
emailIdx: uniqueIndex('users_email_idx').on(table.email),
createdAtIdx: index('users_created_at_idx').on(table.createdAt),
})
);
export const posts = pgTable('posts', {
id: uuid('id').defaultRandom().primaryKey(),
title: text('title').notNull(),
body: text('body'),
published: boolean('published').default(false).notNull(),
authorId: uuid('author_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
});
// Relations (for query builder joins)
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
// Type inference — derive types from schema
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
export type Post = typeof posts.$inferSelect;
export type NewPost = typeof posts.$inferInsert;
// src/db/index.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
const connectionString = process.env.DATABASE_URL!;
// For migrations — disable connection pooling
export const migrationClient = postgres(connectionString, { max: 1 });
// For queries — use pooling
const queryClient = postgres(connectionString);
export const db = drizzle(queryClient, { schema });
// Use Supabase connection pooler (port 6543) for serverless/edge
const connectionString = process.env.DATABASE_URL!;
// DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-us-east-1.pooler.supabase.com:6543/postgres
const client = postgres(connectionString, { prepare: false }); // prepare: false required for pooler
export const db = drizzle(client, { schema });
import { eq, and, or, like, gte, lte, desc, asc, isNull, inArray } from 'drizzle-orm';
// All rows
const allUsers = await db.select().from(users);
// Partial select (typed — only fetches specified columns)
const emails = await db.select({ id: users.id, email: users.email }).from(users);
// Where clause
const user = await db
.select()
.from(users)
.where(eq(users.email, 'user@example.com'))
.limit(1);
// Compound conditions
const activeAdmins = await db
.select()
.from(users)
.where(and(eq(users.active, true), eq(users.role, 'admin')));
// Pagination
const page = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(20)
.offset(40);
// Like / ilike
const results = await db
.select()
.from(users)
.where(like(users.name, '%Example User%')); // case-sensitive
// .where(ilike(users.name, '%example%')); // case-insensitive
// In array
const specific = await db
.select()
.from(users)
.where(inArray(users.id, ['uuid-1', 'uuid-2', 'uuid-3']));
// Single insert with returning
const [newUser] = await db
.insert(users)
.values({
email: 'user@example.com',
name: 'Example User',
role: 'admin',
})
.returning();
// Bulk insert
const newPosts = await db
.insert(posts)
.values([
{ title: 'First Post', authorId: newUser.id },
{ title: 'Second Post', authorId: newUser.id },
])
.returning();
// Upsert (on conflict)
await db
.insert(users)
.values({ email: 'user@example.com', name: 'Example User' })
.onConflictDoUpdate({
target: users.email,
set: { name: 'Example User Updated', updatedAt: new Date() },
});
const [updated] = await db
.update(users)
.set({ name: 'Example User F', updatedAt: new Date() })
.where(eq(users.id, userId))
.returning();
// Update with condition on multiple columns
await db
.update(posts)
.set({ published: true })
.where(and(eq(posts.authorId, userId), eq(posts.published, false)));
const [deleted] = await db
.delete(users)
.where(eq(users.id, userId))
.returning();
// Soft delete pattern
await db
.update(users)
.set({ active: false, updatedAt: new Date() })
.where(eq(users.id, userId));
import { sql } from 'drizzle-orm';
// Inner join
const postsWithAuthors = await db
.select({
postId: posts.id,
title: posts.title,
authorName: users.name,
authorEmail: users.email,
})
.from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.createdAt));
// Left join
const usersWithPosts = await db
.select({
user: users,
postCount: sql<number>`count(${posts.id})::int`,
})
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId))
.groupBy(users.id);
// Nested fetch using relations
const usersWithPosts = await db.query.users.findMany({
where: eq(users.active, true),
with: {
posts: {
where: eq(posts.published, true),
orderBy: [desc(posts.createdAt)],
limit: 5,
},
},
limit: 10,
});
// Returns: User & { posts: Post[] }[]
const result = await db.transaction(async (tx) => {
// All queries inside use the same connection
const [user] = await tx
.insert(users)
.values({ email: 'new@example.com', name: 'New User' })
.returning();
const [post] = await tx
.insert(posts)
.values({ title: 'First Post', authorId: user.id })
.returning();
// Rollback by throwing — transaction auto-rolls back
if (!post) throw new Error('Post creation failed');
return { user, post };
});
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
# Generate migration file from schema changes
npx drizzle-kit generate
# Push schema directly to DB (dev only — skips migration files)
npx drizzle-kit push
# Run pending migrations
npx drizzle-kit migrate
# Open Drizzle Studio (GUI)
npx drizzle-kit studio
# Check diff between schema and DB
npx drizzle-kit check
// scripts/migrate.ts
import { migrate } from 'drizzle-orm/postgres-js/migrator';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const client = postgres(process.env.DATABASE_URL!, { max: 1 });
const db = drizzle(client);
await migrate(db, { migrationsFolder: './drizzle' });
await client.end();
import { sql } from 'drizzle-orm';
// Inline SQL expression
const result = await db
.select({ count: sql<number>`count(*)::int` })
.from(users);
// Full raw query
const rows = await db.execute(
sql`SELECT * FROM users WHERE email ILIKE ${'%' + search + '%'} LIMIT 10`
);
// From schema
type User = typeof users.$inferSelect; // full row
type NewUser = typeof users.$inferInsert; // insert shape (all optional except notNull)
// Partial select — use z.infer or manual Pick
type UserPreview = Pick<User, 'id' | 'name' | 'email'>;
// With relations
type UserWithPosts = typeof users.$inferSelect & {
posts: typeof posts.$inferSelect[];
};
| Task | Pattern |
|---|---|
| Insert + get row | .insert().values().returning() |
| Upsert | .onConflictDoUpdate({ target, set }) |
| Pagination | .limit(n).offset(n) |
| Joins | .innerJoin(table, eq(a.id, b.fk)) |
| Nested data | db.query.table.findMany({ with: {} }) |
| Raw SQL | sql\...`` template tag |
| Multi-table write | db.transaction(async (tx) => { ... }) |
| Supabase pooler | postgres(url, { prepare: false }) |
prisma-patterns — alternative ORMdatabase-schema-designer — schema designdatabase-migration-strategies — migrationsThis skill is indexed by GitNexus for knowledge graph traversal. Index path: /Users/localuser/.claude/skills/drizzle-orm/.gitnexus Last indexed: 2026-05-23