Skip to main content

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

ParameterTypeDescription
getClient() => postgres.SqlFactory returning a new postgres client
organizationTablePgTable & { 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