This skill provides comprehensive Drizzle ORM patterns for PostgreSQL with Vercel Edge Runtime support. Drizzle is Quetrex's chosen ORM because it's edge-first, type-safe, and supports all deployme...
Use when: Working with database operations, schema design, migrations, or queries in Quetrex.
This skill provides comprehensive Drizzle ORM patterns for PostgreSQL with Vercel Edge Runtime support. Drizzle is Quetrex's chosen ORM because it's edge-first, type-safe, and supports all deployment targets.
This skill is organized into focused modules:
Complete query patterns: select, insert, update, delete, joins, pagination, filtering, aggregations, subqueries, CTEs.
When to use:
Transaction patterns: isolation levels, rollback, nested transactions, error handling, deadlock prevention.
When to use:
Relationship patterns: one-to-one, one-to-many, many-to-many, self-referencing, cascading deletes, nested queries.
When to use:
Migration patterns: schema evolution, data migrations, zero-downtime deployments, rollback strategies.
When to use:
Edge deployment patterns: Vercel Edge Functions, Neon serverless, connection pooling, HTTP-based connections.
When to use:
Performance patterns: indexing, query optimization, N+1 prevention, batch operations, caching.
When to use:
TypeScript inference patterns: InferModel, InferSelect, InferInsert, schema types, custom types.
When to use:
Common pitfalls and fixes: SQL injection risks, N+1 queries, missing indexes, transaction deadlocks, type errors.
When to use:
Python script to validate Drizzle queries for common security and performance issues.
When to use:
# Core packages
npm install drizzle-orm @neondatabase/serverless
# Development tools
npm install -D drizzle-kit
// src/lib/db.ts
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);
// src/lib/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: text('email').notNull().unique(),
name: text('name').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// src/services/user-service.ts
import { db } from '@/lib/db';
import { users } from '@/lib/schema';
import { eq } from 'drizzle-orm';
export async function getUserByEmail(email: string) {
return await db.select().from(users).where(eq(users.email, email)).limit(1);
}
import { db } from '@/lib/db';
import { users } from '@/lib/schema';
import { eq, and, gte } from 'drizzle-orm';
const activeUsers = await db
.select()
.from(users)
.where(
and(
eq(users.status, 'active'),
gte(users.createdAt, new Date('2024-01-01'))
)
);
const [newUser] = await db
.insert(users)
.values({
email: 'test@example.com',
name: 'Test User',
})
.returning();
const [updatedUser] = await db
.update(users)
.set({ name: 'Updated Name' })
.where(eq(users.id, 1))
.returning();
await db.transaction(async (tx) => {
const [user] = await tx.insert(users).values({ email, name }).returning();
await tx.insert(profiles).values({ userId: user.id, bio });
});
const usersWithProfiles = await db
.select({
userId: users.id,
userName: users.name,
bio: profiles.bio,
})
.from(users)
.leftJoin(profiles, eq(users.id, profiles.userId));
All database code must have:
Before committing database code:
select * in production codepython validate-queries.py on changed filesBefore committing database code:
select *)If you're migrating from Prisma, see the ADR-002-DRIZZLE-ORM-MIGRATION.md decision record.
Key differences:
For Drizzle-specific questions:
For Quetrex-specific questions:
/docs/architecture/Last Updated: 2025-11-23 by Glen Barnhardt with help from Claude Code