Drizzle ORM

The Schema File

Export converted slim schemas for drizzle-kit migrations.

Point drizzle.config.ts at one file that converts your declarations to real Drizzle objects with toDrizzle. Migrations see only its exports.

import * as DZ from '@mionjs/drizzle-orm-pg-core';
import {sql} from '@mionjs/drizzle-orm';

export const plan = DZ.pgEnum('plan', ['free', 'pro']);
export const invoiceSeq = DZ.pgSequence('invoice_seq', {startWith: 1000});
export const billing = DZ.pgSchema('billing');
export const reader = DZ.pgRole('reader').existing();

export const accounts = DZ.pgTable(
  'accounts',
  {
    id: DZ.uuid('id', {defaultRandom: true, primaryKey: true}),
    email: DZ.varchar('email', {length: 200, notNull: true}),
    plan: plan('plan', {notNull: true, default: ['free']}),
    spend: DZ.numeric('spend', {precision: 10, scale: 2, mode: 'number'}),
  },
  (t) => [
    DZ.uniqueIndex('accounts_email_uidx').on(t.email),
    DZ.check('accounts_spend_check', sql`${t.spend} >= 0`),
    DZ.pgPolicy('accounts_reader', {
      for: 'select',
      to: reader,
      using: sql`true`,
    }),
  ]
).enableRLS();

export const paidAccounts = DZ.pgView('paid_accounts', {
  id: DZ.uuid('id'),
  email: DZ.varchar('email', {length: 200, notNull: true}),
}).as(sql`select id, email from ${accounts} where plan = 'pro'`);

export const auditPolicy = DZ.pgPolicy('accounts_audit', {
  for: 'select',
  to: 'postgres',
  using: sql`true`,
}).link(accounts);

Standalone Objects

Materializing a table or view also covers its columns, indexes, constraints and inline policies. drizzle-kit reads standalone objects on their own, so each one needs its own toDrizzle call:

Declared withMaterialize
pgTable, pgView, pgMaterializedViewthe table or view itself
pgEnum, pgSequence, pgSchema, pgRoleeach handle
pgPolicy(...).link(table)the policy itself
pgPolicy inside a table's third argumentnothing, it comes with the table

Importing Types in Your App

Your routes, models and client never import this file. They take their types from the schema module that declares the tables:

import {accounts} from './schema.ts';
import type {InferSelectModel} from '@mionjs/drizzle-orm';

export type Account = InferSelectModel<typeof accounts>;

The file above is the only one that loads Drizzle, and it only runs when you generate or apply migrations.

Copyright © 2026