drizzle
LobeHub Drizzle ORM schema and query style. Use for pgTable schemas, indexes, joins, inferred types, db.select/db.query, schema fields, foreign keys, junction tables, or postgres query patterns.
Security Assessment
About drizzle
The Drizzle ORM Schema Style Guide codifies how LobeHub defines PostgreSQL tables, columns, and queries with Drizzle. It documents where schema code lives: schemas under packages/database/src/schemas/, migrations under packages/database/migrations/, and configuration in drizzle.config.ts using the postgresql dialect in strict mode. Shared helpers in _helpers.ts provide timestamptz, createdAt, updatedAt, accessedAt, and a spreadable timestamps object.
Naming follows plural snake_case tables and snake_case columns, and new tables should preserve the established noun family and suffix (for example workspace_xxx_logs alongside user_xxx_logs). For columns, the guide steers away from auto-incrementing primary keys (serial/bigserial) because sequence state is fragile across migrations and restores, preferring application-generated text IDs (idGenerator, createNanoId) or uuid for internal tables while keeping $defaultFn so explicit inserts can still override the id. It also discourages sentinel strings for missing values in favor of nullable columns or concrete status types, discourages pgEnum in favor of text/varchar with a TypeScript $type value type kept in a shared module, recommends JSDoc on non-obvious fields, and requires concrete interfaces for JSONB columns instead of loose Record types. Indexes use the array-return style.
Reach for this guide when writing or reviewing pgTable schemas, foreign keys with onDelete cascade, junction/many-to-many tables, indexes, or inferred insert and select types via createInsertSchema and $inferInsert/$inferSelect. It also reminds contributors that every new model or repository file needs a matching sibling test in the same pull request.
FAQ
Where do schema files, migrations, and config live?
Schemas sit under packages/database/src/schemas/, migrations under packages/database/migrations/, and configuration in drizzle.config.ts using the postgresql dialect with strict mode.
Why does the guide discourage serial primary keys?
Auto-incrementing keys create fragile sequence state during cross-database migrations, restores, and data copy jobs; it prefers application-generated text IDs or uuid for internal tables.
Should I use pgEnum for status columns?
No, it defaults to text() or varchar() with a TypeScript $type value type kept in a shared module, since database enums are expensive to evolve safely.
How should JSONB columns be typed?
Define a concrete interface describing the expected shape rather than a loose Record type, so callers, migrations, and review queries stay aligned on one contract.
Do new models or repositories need tests?
Yes, every new file under packages/database/src/models or src/repositories needs a matching sibling test file shipped in the same PR.
Install drizzle
Quick Setup:
- Copy the skill folder to
.claude/skills/ - Claude will automatically detect and use the skill
Repository
lobehub/lobehub