drizzle-sqlite
Drizzle ORM targeting SQLite (better-sqlite3, libsql/Turso, bun:sqlite, Cloudflare D1, expo-sqlite, op-sqlite). Covers schema definition (column modes, primary keys, foreign keys, indexes), drizzle-kit migrations (generate vs push, renames, custom SQL), the query builder (selects, upserts, returning, EXPLAIN), the relational query builder (relations(), `with`, partial columns), transactions and `db.batch()`, prepared statements with `sql.placeholder()`, connection pragmas (WAL, foreign_keys, busy_timeout), and Drizzle type inference (`$inferSelect`, `$inferInsert`, `$type<>`, drizzle-zod). Use when writing, reviewing, or refactoring Drizzle code for SQLite. Trigger even if the user doesn't say "performance" — schema/migration choices made now are expensive to reverse later, and SQLite-specific traps (single-writer model, no native booleans/dates, ALTER TABLE limits, FK pragma off by default) catch teams who reach for Drizzle without reading the SQLite docs.
How do I install this agent skill?
npx skills add https://github.com/pproenca/dot-skills --skill drizzle-sqliteIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill is a comprehensive technical reference for Drizzle ORM with SQLite backends. It provides educational guidance on schema definition, migrations, query optimization, and type safety. No security risks were identified.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
dot-skills Drizzle SQLite Best Practices
Library-reference skill for Drizzle ORM with SQLite-family backends. 45 rules across 8 categories, ordered by execution-lifecycle impact: schema → migrations → query → relations → transactions → performance → connection → types.
When to Apply
Reference these guidelines when:
- Defining
sqliteTableschemas — choosing column types, primary keys, indexes, foreign keys - Running
drizzle-kit generate/migrate/push, or hand-editing a migration SQL file - Writing queries with
db.select(),db.insert(),db.update(),db.delete() - Reaching for nested data with
db.query.*and the relational query builder - Wrapping multi-statement writes in
db.transaction()ordb.batch()(libsql/Turso/D1) - Optimizing a hot-path query with
.prepare()+sql.placeholder()or covering indexes - Setting up the Drizzle client (pragmas, driver choice, singleton lifecycle)
- Wiring database types into application code (
$inferSelect, drizzle-zod, JSON shapes)
The skill is not specific to one driver — it covers behavior shared across better-sqlite3, libsql, bun:sqlite, expo-sqlite, op-sqlite, and Cloudflare D1, calling out driver-specific deviations where they exist.
Architectural Context
SQLite is unusual among production databases:
- No client/server. The "connection" is a file open. There is no connection pool, no auth, no network in the local-file case.
- Single writer. One writer at a time, no matter how many connections. Reads can be parallel under WAL.
- No native booleans or dates. Everything is
INTEGER,REAL,TEXT,BLOB, orNULL— Drizzle column modes encode the rest. - Limited
ALTER TABLE. OnlyRENAME COLUMN,ADD COLUMN,DROP COLUMN. Type changes and constraint additions need a table rebuild. - Foreign keys off by default.
PRAGMA foreign_keys = ONis per-connection and not persistent.
Many rules in this skill exist because Drizzle's API abstracts over PostgreSQL/MySQL/SQLite uniformly — but the underlying SQLite engine has constraints that show up at runtime if you treat it like Postgres.
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Schema Definition | CRITICAL | schema- |
| 2 | Migrations & Drizzle Kit | CRITICAL | migrate- |
| 3 | Query Building | HIGH | query- |
| 4 | Relations | HIGH | rel- |
| 5 | Transactions & Batching | MEDIUM-HIGH | tx- |
| 6 | Prepared Statements & Hot Paths | MEDIUM-HIGH | perf- |
| 7 | Connection & Driver Setup | MEDIUM | conn- |
| 8 | Type Inference | MEDIUM | types- |
Quick Reference
1. Schema Definition (CRITICAL)
schema-integer-for-booleans— Useinteger({ mode: 'boolean' })so the inferred type isboolean, not0 | 1schema-timestamp-mode-for-dates— Store dates asinteger({ mode: 'timestamp_ms' }), not textschema-always-primary-key— Declare an explicit PK (single or composite); don't rely on hidden rowidschema-foreign-keys-with-actions— SpecifyonDelete/onUpdateon every.references()schema-index-foreign-keys-and-lookups— Index FK columns and frequentWHEREs — SQLite does not auto-index FKsschema-text-json-not-blob-json— Usetext({ mode: 'json' })sojson_extractand JSON-path indexes workschema-unique-constraints-for-natural-keys—.unique()for email/slug/externalId so onConflict has a target
2. Migrations & Drizzle Kit (CRITICAL)
migrate-generate-not-push-in-prod— Usegenerate + migrate;pushdrops columns it can't reconcilemigrate-explicit-renames— Answer the rename prompt — defaults treat renames as drop+addmigrate-config-dialect-and-out— Definedrizzle.config.tsso commands work without flagsmigrate-apply-with-migrator— Apply viadrizzle-kit migrateor the drivermigratormodule, not raw SQLmigrate-data-backfill-as-custom-sql— Hand-edit migration SQL to backfill atomically with the DDLmigrate-commit-migrations-to-git— Commitdrizzle/SQL anddrizzle/meta/snapshots — both are required
3. Query Building (HIGH)
query-select-columns-not-star— Project to the columns you need withdb.select({ ... })query-avoid-n-plus-one-with-inarray— Replace looped queries withinArray()query-always-limit-listings— Every listing query needs.limit()(and ideally a cursor)query-bind-parameters-not-concat— Useeq()/ sql template — never string-concat valuesquery-upsert-with-onconflict— Atomic upserts via.onConflictDoUpdate(), not select-then-writequery-returning-instead-of-reselect—.returning()on insert/update/delete saves a round tripquery-toSQL-and-explain— Inspect generated SQL andEXPLAIN QUERY PLANon hot paths
4. Relations (HIGH)
rel-declare-relations-for-rqb—relations()declarations unlockdb.query.*andwithrel-prefer-with-over-manual-joins—withfor nested fetches; manual joins lose typing and add coderel-partial-columns-in-with—columns: { ... }insidewithto limit payload and avoid leaksrel-filter-with-where-inside-with— Push related-row filters intowith.where, not into JSrel-leftjoin-for-flat-aggregates— Drop toleftJoin+groupBywhen you need aggregates
5. Transactions & Batching (MEDIUM-HIGH)
tx-wrap-multi-statement-writes— Wrap related writes indb.transaction()for atomicity + throughputtx-batch-for-libsql-roundtrips—db.batch()on libsql/Turso/D1 collapses N round trips into 1tx-no-network-io-inside-transaction— No awaited HTTP / FS / Stripe calls inside a transactiontx-handle-busy-with-retry— Bounded retries onSQLITE_BUSY— only on transient errorstx-single-writer-no-parallel-writes—Promise.allof writes contends; serialize them
6. Prepared Statements & Hot Paths (MEDIUM-HIGH)
perf-prepare-hot-paths—.prepare()+sql.placeholder()for queries running on every requestperf-bulk-insert-multi-row-values— Onevalues([...rows])instead of N looped insertsperf-avoid-count-star-on-large-tables— Counter rows or keyset pagination instead ofcount(*)perf-keyset-not-offset-for-deep-pages— Keyset pagination keeps cost constant across pagesperf-covering-index-for-hot-queries— Cover the projected columns so the planner skips the row read
7. Connection & Driver Setup (MEDIUM)
conn-enable-wal—journal_mode = WALfor concurrent reads + one writerconn-set-busy-timeout—busy_timeout = 5000turns contention into a waitconn-foreign-keys-pragma—foreign_keys = ONper connection — off by defaultconn-singleton-client— Module-scope singleton; never per-request constructionconn-pick-driver-deliberately— Sync vs async vs HTTP — choose by deployment target
8. Type Inference (MEDIUM)
types-infer-select-insert— Derive row types with$inferSelect/$inferInserttypes-narrow-json-with-dollartype—.$type<Shape>()to escapeunknownon JSON columnstypes-getTableColumns-for-reuse— Share projections viagetTableColumns()+ spreadtypes-drizzle-zod-for-runtime-validation—createInsertSchema(table)derives a Zod validator from the schematypes-bigint-mode-for-large-integers—mode: 'bigint'for IDs overNumber.MAX_SAFE_INTEGER
How to Use
Read the relevant category overview in references/_sections.md, then the specific rule files for detailed explanations and code examples. Each rule has incorrect-vs-correct examples — apply the correct pattern to the code under review.
For complex changes (schema redesign, migration strategy, performance work), read all rules in the affected category before deciding.
- Section definitions — Category structure and impact levels
- Rule template — Template for adding new rules
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |
Related Skills
effect-ts— When the application is Effect-based; Drizzle integrates viaEffect.tryPromise.nextjs-bundle-optimizer— For Next.js apps reaching for SQLite as the data layer.better-auth— Often paired with Drizzle SQLite for auth tables; seebetter-auth-scaffoldfor table generation.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/pproenca/dot-skills/drizzle-sqlite">View drizzle-sqlite on skillZs</a>