Drizzle
Auto-generate a Permix definition and CRUD rules from your Drizzle schema
Overview
Permix ships with a Drizzle integration that takes your existing Drizzle schema and produces a fully type-safe Permix instance with one permission entity per table. By default each table receives the four CRUD actions (create, read, update, delete), but the action list can be customised.
Two entry points are exposed so you can choose the one that matches your installed Drizzle version:
| Import path | Drizzle version | Notes |
|---|---|---|
permix/drizzle | v1 (>=1.0.0-rc) | Uses Drizzle's official extractTablesFromSchema helper. Detects tables and views. |
permix/drizzle/legacy | v0 (>=0.30 <1) | Detects tables only via is(value, Table). |
Both entry points expose the same API surface, so migrating between them is a one-line import change once you upgrade Drizzle.
Before getting started with the Drizzle integration, make sure you've completed the initial setup steps in the Quick Start guide.
Setup
Define your Drizzle schema as usual, then create a Permix instance from it.
Drizzle v1
import { } from 'drizzle-orm'
import { , , , } from 'drizzle-orm/pg-core'
import { } from 'permix/drizzle'
const = ('users', {
: ('id').(),
: ('name').(),
})
const = ('posts', {
: ('id').(),
: ('title').(),
: ('author_id').().(() => .),
})
const = ({ , }, => ({
: { : ..({ : .., : .. }) },
}))
const = { , , }
const = ()
.({
: { : true, : true, : false, : false },
: { : true, : true, : true, : false },
})
.('users.read') // true
.('posts.delete') // falseDrizzle v0
import { } from 'drizzle-orm/_relations'
import { , , , } from 'drizzle-orm/pg-core'
import { } from 'permix/drizzle/legacy'
const = ('users', {
: ('id').(),
: ('name').(),
})
const = ('posts', {
: ('id').(),
: ('title').(),
: ('author_id').().(() => .),
})
const = (, ({ }) => ({
: (),
}))
const = { , , }
const = ()
.({
: { : true, : true, : false, : false },
: { : true, : true, : true, : false },
})
.('users.read') // true
.('posts.delete') // falseThe returned instance is a regular Permix object, so every API you already know — check, setup, template, dehydrate, hydrate, hook, isReady, etc. — is available unchanged.
Customising Actions
If CRUD isn't quite what you want, pass an explicit actions tuple. Use as const so the literal action names flow through to your check sites:
const permix = createPermix(schema, {
actions: ['view', 'edit', 'archive'] as const,
})
permix.setup({
users: { view: true, edit: false, archive: false },
posts: { view: true, edit: true, archive: false },
})
permix.check('posts.edit') // true
permix.check('users.archive') // falseDiscovering Tables and Actions at Runtime
Both the detected table list and the action list are exposed on the instance, which is handy for building UIs or seeding rules dynamically:
const permix = createPermix(schema)
permix.tables // ['users', 'posts', ...]
permix.actions // readonly ['create', 'read', 'update', 'delete']Notes
- v1 detects both tables and views (via Drizzle's
extractTablesFromSchema). v0 detects tables only. - Both versions skip non-entity exports automatically, so
import * as schemaworks as-is. In v1 adefineRelations(...)object is filtered out; in v0 the same is true ofrelations(...)calls. - Tables from any Drizzle dialect (
drizzle-orm/pg-core,drizzle-orm/mysql-core,drizzle-orm/sqlite-core) are detected, so a single schema can mix dialects if needed. - Drizzle is declared as an optional peer dependency. You only need to install it if you plan to use a
permix/drizzle*entry point. - The permission keys default to the schema export names, not the SQL table names. If you exported
pgTable('app_users', { ... })asusers, you checkusers.read, notapp_users.read.