Migrations
Identity
Section titled “Identity”Generated API package scripts backed by Drizzle Kit, plus the programmatic
ledger helpers @sapporta/server exports.
Contract
Section titled “Contract”db:generate --name <name>writes SQL, journal, and snapshot artifacts underpackages/api/migrations/. Review the generated SQL and snapshot before applying them.db:migrateapplies pending committed artifacts to the configured SQLite database.db:checkrunsdrizzle-kit check. It validates the Drizzle migration snapshot chain; it does not inspect live tables or prove that migrations were applied.- Server startup separately checks migration files against the applied ledger and does not apply migrations automatically. An application that names its own migrations directory may apply them itself; see Apply migrations from application code.
- Every
db:*script openssqlite.dbin the directory named bySAPPORTA_DATA_DIR, read from the environment. The scripts never load.env.development, anddrizzle.config.tsstops with an error when the variable is unset.
Minimal lookup
Section titled “Minimal lookup”SAPPORTA_DATA_DIR=data pnpm --filter ./packages/api db:generate --name add_fieldSAPPORTA_DATA_DIR=data pnpm --filter ./packages/api db:migrateSAPPORTA_DATA_DIR=data pnpm --filter ./packages/api db:checkApply migrations from application code
Section titled “Apply migrations from application code”An application packaged as one module, which ships its migrations inside that
package and migrates the user’s database itself, does not use the generated
db:* scripts. @sapporta/server exposes the same ledger logic:
import { applyMigrations, pendingMigrations } from "@sapporta/server";
const pending = pendingMigrations(sqlite, migrationsDir);if (pending.length > 0) applyMigrations(sqlite, migrationsDir);pendingMigrations(sqlite, migrationsDir)lists the migrations the database has not applied, oldest first.applyMigrations(sqlite, migrationsDir)applies them with drizzle-orm’smigrate()and returns the ones it applied. It throws, and applies nothing, when a pending migration is dated before the latest applied one, becausemigrate()would skip that migration without an error.assertMigrationsReadyandloadSapportaProjecttakemigrationsDir, which defaults topackages/api/migrationsunder the project root. Thepnpm --filterhints in a readiness error appear only for that default.