Migrations
createMigrationHelpers returns functions for running Drizzle migrations in a multi-tenant architecture with separate global and tenant schemas.
createMigrationHelpers
import { createMigrationHelpers } from '@repo/db'
import postgres from 'postgres'
const { migrateGlobals, migrateTenant, migrate } = createMigrationHelpers(
() => postgres(DATABASE_URL),
organizationTable, // PgTable with a string `id` column
)
Parameters
| Parameter | Type | Description |
|---|---|---|
getClient | () => postgres.Sql | Factory returning a new postgres client |
organizationTable | PgTable & { id: AnyPgColumn<{ data: string, notNull: true }> } | Table used to look up tenant IDs |
Returned Functions
migrateGlobals
Runs migrations from ./drizzle/global against the database.
await migrateGlobals()
migrateTenant
Runs tenant-scoped migrations from ./drizzle/tenant. Replaces the tenant placeholder in migration files with the actual tenant ID. Pass a specific tenant ID or omit to migrate all tenants.
// Single tenant
await migrateTenant('tenant-123')
// All tenants (queries organizationTable for IDs)
await migrateTenant()
Internally, migration files are copied to a temp directory with placeholders replaced, then cleaned up after migration.
migrate
Convenience function that runs migrateGlobals() then migrateTenant() (all tenants).
await migrate()
Directory Structure
The migration system expects:
drizzle/
global/ # Global schema migrations
tenant/ # Tenant schema migrations (contain placeholder strings)
Generate migrations using the package scripts:
pnpm db:generate:global
pnpm db:generate:tenant