Cursor plugin for Drizzle ORM (drizzle-orm@0.45.x stable + 1.0.0-rc.x next). Teaches schema-first design, drizzle-kit migrate vs push vs pull, the sql template tag for parameter binding, drizzle-zod validation pairing, Postgres RLS / materialised views / sequences, Testcontainers transaction-rollback tests. Catches the 20 LLM regressions that come from Prisma muscle memory and pre-2025 Drizzle training data.
LLMs trained on early Drizzle codebases plus a lot of Prisma produce code that does not type-check or that ships SQL injection. They write:
- Prisma
include: { posts: true }insidedb.query.users.findMany(...)(Drizzle useswith:) - Prisma
select: { id: true }inside the same (Drizzle usescolumns:) - Prisma nested
where: { user: { name: "x" } }filter shape (Drizzle uses callback +exists) - **
db.execute(\SELECT * FROM users WHERE email = '${email}'`)** (SQL injection; usesql`...${email}``) drizzle-kit generate:pgin package.json scripts (deprecated; usedrizzle-kit generate)drizzle-kit pushin production deploy scripts (writes diff with no migration history; usemigrate)casing: "camelCase"on thedrizzle()constructor when on v1.0-rc (removed; use per-tablecamelCase.table())from "drizzle-orm/pg-core/utils"import ofpgArraywhen on v1.0-rc (path moved to/array)pgTable("users", {...}, (t) => ({ keyName: ... }))returned-object index shape against 0.31+ (returns array now)pgTableimported fromdrizzle-orm/postgres-js(driver, not schema namespace; usepg-core).returning()on MySQL or Cloudflare D1 inserts (Postgres-only; better-sqlite3 has it, D1 does not yet)- Missing
awaitondb.select() / .insert() / .execute()chains (returns QueryBuilder, not data) relations()declared in the same file aspgTable(circular import risk)- Composite primary key shape:
primaryKey(t.a, t.b)instead ofprimaryKey({ columns: [t.a, t.b] }) pgEnumused as a TypeScript type instead of branding with$type<T>()select().from(users).leftJoin(posts, ...)consumed as flat rows when default shape is nested- Transaction callback using outer
db.Xinstead of thetxargument (escapes the transaction) drizzle-orm< 0.45.2 still installed (CVE insql.identifier()/sql.as()escaping)select()withleftJoinon a 1:N when distinct user rows are wanted (useselectDistinct+ projection, orgroupByfor aggregates)- Hand-translating an existing database to TypeScript when
drizzle-kit pulldoes it in one command
A basic Drizzle rules file already exists on cursor.directory. It is shallow: generic "use Drizzle, prefer types, write migrations" guidance with no version awareness, no anti-patterns, no fixtures. This plugin is the depth play:
- 20 documented anti-patterns with BAD/CORRECT TS code (the existing rule has none)
- Two version profiles -
0.45.xstable (npmlatesttoday) and1.0-rcnext - with deltas called out inline - Migration skill from v0 to v1-rc with concrete sed commands and step ordering
- Postgres-specific rules broken out (RLS, materialised views, sequences, identity columns, JSONB operators)
- Multi-dialect awareness per rule (Postgres / MySQL / SQLite / D1 specifics flagged)
- Reviewer agent with severity grouping (CRITICAL / ERROR / WARN / SUGGESTION)
- Compilable test fixtures (anti-pattern + correct sample)
drizzle-kitcommand awareness as a first-class rule (generate:pgerrors today;pushvsmigratefor prod has caused outages)
Copy the rules, skills, and agents into your project's Cursor configuration:
git clone https://github.com/RoninForge/roninforge-drizzle.git
cp -r roninforge-drizzle/rules/* your-project/.cursor/rules/
cp -r roninforge-drizzle/skills/* your-project/.cursor/skills/
cp -r roninforge-drizzle/agents/* your-project/.cursor/agents/Or vendor the whole repo as a git submodule under your-project/.cursor/plugins/. Refer to the Cursor plugin docs for the current global-install path on your Cursor version.
| Rule | Scope | What it does |
|---|---|---|
drizzle-core |
Always active | Schema-first design, separated relations file, sql template tag, $inferSelect/$inferInsert, drizzle-zod pairing, transaction semantics, v1.0-rc deltas inline |
drizzle-anti-patterns |
Always active | 20 LLM regressions: Prisma include/select/nested-where, removed casing API, deprecated drizzle-kit commands, SQL injection via execute, .returning() on MySQL, missing await, push in prod, pre-0.45.2 CVE |
drizzle-postgres |
**/*.ts |
RLS via pgPolicy + enableRLS / withRLS, materialised views, sequences, identity columns, JSONB operators, generated columns, driver trade-offs |
drizzle-migrations |
drizzle.config.ts + drizzle/ + migrations | drizzle-kit four commands (generate / migrate / push / pull), config shape, snapshot files, applying in CI/prod |
drizzle-testing |
Agent-requested | Testcontainers Postgres + transaction rollback, in-memory pglite, drizzle-zod runtime validators, what to mock and what not |
| Skill | Command | What it does |
|---|---|---|
| New schema | /drizzle-new-schema |
Scaffold table with identity column, $onUpdate timestamp, indexes-as-array, $infer types, drizzle-zod validator, separate relations file |
| Migrate to v1 | /drizzle-migrate-to-v1 |
0.x to 1.0-rc migration: bump pin, codemod pgArray import, codemod casing, defineRelations rewrite, regenerate snapshots |
| Validate | /drizzle-validate |
Scan codebase for the 20 tracked anti-patterns, severity-tagged report |
| RLS | /drizzle-rls |
Scaffold Postgres RLS: pgPolicy declarations, enableRLS / withRLS, owner / tenant / public-read patterns, request-scoped auth context, isolation tests |
| Agent | What it does |
|---|---|
drizzle-reviewer |
Reviews Drizzle TS by severity: critical (security, data loss), error (won't compile or wrong runtime), warning (regressions), suggestion (style + future-proofing) |
tests/fixtures/anti-pattern-sample/ is a Drizzle 0.34 / drizzle-kit 0.21 trash fire: serial() PKs, relations() mixed with schema, third-arg returned object (won't compile against 0.31+), casing: "camelCase", SQL injection via db.execute, Prisma-style include:, missing await, transaction escape via outer db. The package.json ships the deprecated generate:pg and push:pg scripts plus drizzle-kit push as the deploy step.
tests/fixtures/correct-sample/ is the same shape rewritten on drizzle-orm@0.45.2: defineConfig drizzle.config.ts with strict: true, identity columns, schema split per file with separate relations.ts, sql\`template tag,with:for related entities,awaiton every chain,txinside transactions,drizzle-zod` validators, singleton pool sized for serverless.
MIT - see LICENSE