drizzle-orm

Drizzle ORM for type-safe SQL with PostgreSQL, MySQL, and SQLite. Use when defining schemas, writing queries, managing relations, running migrations, or using drizzle-kit. Use for drizzle, orm, schema, query, migration, pgTable, relations, drizzle-kit, drizzle-zod.

oakoss/agent-skills148 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: drizzle-orm
description: Drizzle ORM for type-safe SQL with PostgreSQL, MySQL, and SQLite. Use when defining schemas, writing queries, managing relations, running migrations, or using drizzle-kit. Use for drizzle, orm, schema, query, migration, pgTable, relations, drizzle-kit, drizzle-zod.
license: MIT
---

# Drizzle ORM

## Overview

Drizzle ORM is a lightweight, type-safe TypeScript ORM that maps directly to SQL for PostgreSQL, MySQL, and SQLite. It provides both a SQL-like query builder and a relational queries API, with zero dependencies and full serverless compatibility. Use Drizzle when you need compile-time type safety with SQL-level control; avoid it when you need a full active-record ORM with automatic migrations (use Prisma) or when working with MongoDB/NoSQL databases.

## Quick Reference

| Pattern             | API                                                                    | Key Points                                            |
| ------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------- |
| Schema definition   | `pgTable('name', { columns }, (t) => [indexes])`                       | Third arg returns array of indexes/constraints        |
| Column types        | `text()`, `integer()`, `boolean()`, `timestamp()`                      | Import from `drizzle-orm/pg-core`                     |
| Type inference      | `typeof table.$inferSelect`, `$inferInsert`                            | Derive TS types directly from schema                  |
| Relational queries  | `db.query.table.findMany({ with, where })`                             | Requires schema passed to `drizzle()` client          |
| SQL-like queries    | `db.select().from(table).where()`                                      | Chainable, returns array of rows                      |
| Insert              | `db.insert(table).values({}).returning()`                              | `.returning()` for getting inserted rows              |
| Update              | `db.update(table).set({}).where().returning()`                         | Always include `.where()` to avoid full-table updates |
| Delete              | `db.delete(table).where()`                                             | Always include `.where()` to avoid full-table deletes |
| Upsert              | `.onConflictDoUpdate({ target, set })`                                 | Chain after `.insert().values()`                      |
| Transactions        | `db.transaction(async (tx) => { ... })`                                | Auto-rollback on thrown errors                        |
| Filters             | `eq()`, `and()`, `or()`, `inArray()`, `sql\`\``                        | Import operators from `drizzle-orm`                   |
| Relations           | `relations(table, ({ one, many }) => ({}))`                            | Declares logical relations for relational queries     |
| Generate migrations | `drizzle-kit generate`                                                 | Creates SQL migration files from schema diff          |
| Apply migrations    | `drizzle-kit migrate` or `migrate()` in code                           | Applies pending migrations to database                |
| Push schema         | `drizzle-kit push`                                                     | Direct schema push without migration files            |
| Prepared statements | `db.select().from(t).where(eq(t.id, sql.placeholder('id'))).prepare()` | Reusable parameterized queries                        |
| Views               | `pgView('name').as(qb => ...)`                                         | Regular and materialized views                        |
| $count utility      | `db.$count(table, filter?)`                                            | Shorthand count, usable as subquery                   |
| Generated columns   | `text().generatedAlwaysAs(() => sql\`...\`)`                           | Computed columns (virtual or stored)                  |
| Check constraints   | `check('name', sql\`condition\`)`                                      | Row-level validation at database level                |

## Common Mistakes

| Mistake                                            | Correct Pattern                                                       |
| -------------------------------------------------- | --------------------------------------------------------------------- |
| Missing `.returning()` on insert/update            | Chain `.returning()` to get back inserted/updated rows                |
| Omitting `.where()` on update/delete               | Always provide `.where()` to avoid affecting all rows                 |
| Using `any` for query result types                 | Use `$inferSelect` / `$inferInsert` for type-safe results             |
| Not passing `schema` to `drizzle()` client         | Pass `{ schema }` to enable `db.query` relational API                 |
| Forgetting indexes on foreign key columns          | Add explicit indexes for columns used in joins/lookups                |
| Wrapping related writes without a transaction      | Use `db.transaction()` for multi-table mutations                      |
| Using raw column names with `casing: 'snake_case'` | With casing option, define columns in camelCase without name arg      |
| Declaring relations but missing the inverse        | Both sides of a relation need declarations for relational queries     |
| Using `serial()` in new PostgreSQL schemas         | Prefer `integer().generatedAlwaysAsIdentity()` (modern approach)      |
| Not handling `findFirst` returning `undefined`     | Check for `undefined` before accessing properties                     |
| Importing column types from wrong dialect module   | Use `drizzle-orm/pg-core` for PostgreSQL, `mysql-core`, `sqlite-core` |
| Using `.references()` instead of `relations()`     | `.references()` is SQL foreign key; `relations()` is for query API    |

## Delegation

> If the `tanstack-query` skill is available, delegate client-side caching and server state management to it.
> Otherwise, recommend: `npx skills add oakoss/agent-skills --skill tanstack-query`
>
> If the `tanstack-start` skill is available, delegate server function patterns for database access to it.
> Otherwise, recommend: `npx skills add oakoss/agent-skills --skill tanstack-start`
>
> If the `electricsql` skill is available, delegate Electric setup, shape configuration, and write patterns to it.
> Otherwise, recommend: `pnpm dlx skills add oakoss/agent-skills -s electricsql -a claude-code -y`
>
> If the `pglite` skill is available, delegate PGlite-specific configuration, extensions, and browser storage patterns to it.
> Otherwise, recommend: `pnpm dlx skills add oakoss/agent-skills -s pglite -a claude-code -y`

- **Schema validation**: Use `drizzle-zod` to generate Zod schemas from Drizzle tables for input validation
- **Query pattern discovery**: Use `Explore` agent
- **Code review**: Delegate to `code-reviewer` agent

## References

- [Schema definition, column types, constraints, indexes, and type inference](references/schema-definition.md)
- [Relational queries, SQL-like API, joins, subqueries, and aggregations](references/queries.md)
- [Insert, update, delete, upsert, and transactions](references/mutations.md)
- [Relations: one, many, nested with clauses, self-referencing](references/relations.md)
- [Migrations: drizzle-kit generate, migrate, push, pull, studio](references/migrations.md)
- [Filter operators: eq, ne, gt, lt, like, inArray, sql template](references/filters-and-operators.md)
- [Views, materialized views, generated columns, check constraints, $count, batch API](references/views-and-advanced.md)
- [ElectricSQL + PGlite integration: driver setup, schema-to-shape mapping, type inference, local sync](references/electric-integration.md)

More Database skills

supabase-postgres-best-practices

supabase/agent-skills

Postgres best practices maintained by Supabase, for Postgres running anywhere. Load this skill BEFORE writing or changing anything that lives in a Postgres database: creating or altering tables and columns (including choosing column types), schema design, migrations and declarative schema files, RLS policies and the tests that verify them, indexes, triggers, database functions, queues and scheduled jobs (pg_cron, pgmq), vector/semantic search (pgvector), and restoring dumps (pg_restore) or importing data. Also load it when diagnosing slow queries, high CPU, timeouts, EXPLAIN plans, connection exhaustion, locking, bloat, or rows visible to the wrong user or tenant. This is not just a performance guide — schema, migration, security, and SQL authoring tasks need these rules too, even for a one-column change or a single query.

372.5k

prisma-database-setup

prisma/skills

Guides for configuring Prisma with different database providers (PostgreSQL, MySQL, SQLite, MongoDB, etc.). Use when setting up a new project, changing databases, or troubleshooting connection issues. Triggers on "configure postgres", "connect to mysql", "setup mongodb", "sqlite setup".

241.5k

prisma-postgres

prisma/skills

Prisma Postgres setup and operations guidance across Console, create-db CLI, Management API, and Management API SDK. Use when creating Prisma Postgres databases, working in Prisma Console, provisioning with create-db/create-pg/create-postgres, or integrating programmatic provisioning with service tokens or OAuth.

235.0k

← All Database skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY