UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

165 lines (125 loc) 5.13 kB
# Migrations Reference Built-in online data migrations for kitcn. Prerequisites: `setup/server.md`. ## When to Migrate Convex is not SQL — skip migrations for backward-compatible changes. **Skip migrations:** - Adding optional fields - Adding new tables or indexes - Code-level defaults on read (`doc.field ?? 'default'`) - Keeping deprecated fields while new code rolls out **Use migrations:** - Optional → required (field must exist on every row) - Type or enum narrowing - Field rename or removal that would violate schema - Semantic rewrites or one-time backfills **Rule:** Old docs still pass schema + app logic → no migration. Old docs would fail → migrate. ## Core API ### `defineMigration` ```ts import { defineMigration } from 'kitcn/orm'; export const migration = defineMigration({ id: '20260227_080239_backfill_todo_priority', // timestamped unique id description: 'backfill todo priority', // optional up: { table: 'todos', migrateOne: async (_ctx, doc) => { if (doc.priority === undefined || doc.priority === null) { return { priority: 'medium' }; // partial patch } // return nothing to skip }, }, down: { // optional — omit if not safely reversible table: 'todos', migrateOne: async (_ctx, doc) => { if (doc.priority === 'medium') { return { priority: undefined }; } }, }, }); ``` ### MigrationStep Fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `table` | `string` | — | Table to iterate | | `migrateOne` | `(ctx, doc) => patch \| void` | — | Per-document transform | | `batchSize` | `number` | `128` (runtime) / `256` (CLI) | Docs per batch | | `writeMode` | `'safe_bypass' \| 'normal'` | `'safe_bypass'` | Bypass or run ORM rules/triggers | ### `migrateOne` Context | Field | Type | Description | |-------|------|-------------| | `db` | `DatabaseWriter` | Raw Convex database writer | | `orm` | `OrmWriter` | ORM writer for complex ops | | `migrationId` | `string` | Current migration id | | `runId` | `string` | Current run id | | `direction` | `'up' \| 'down'` | Current direction | | `dryRun` | `boolean` | Whether dry run | | `writeMode` | `'safe_bypass' \| 'normal'` | Current write mode | ### `defineMigrationSet` Auto-generated manifest. Collects migrations, computes checksums, sorts by id: ```ts import { defineMigrationSet } from 'kitcn/orm'; export const migrations = defineMigrationSet([migration1, migration2]); ``` ## CLI Commands | Command | Description | |---------|-------------| | `migrate create <name>` | Scaffold timestamped migration + update manifest | | `migrate up [--prod]` | Apply all pending migrations in order | | `migrate down --steps N [--prod]` | Roll back N migrations | | `migrate down --to <id> [--prod]` | Roll back to specific migration | | `migrate status [--prod]` | Show applied/pending/drift state | | `migrate cancel [--prod]` | Cancel active run | ## Deploy Integration `kitcn deploy` auto-runs: `convex deploy``migrate up``aggregate backfill`. Convex deploy flags pass through first, including `--message` for deployment history and `--preview-name` for reusable preview deployments. Config in `kitcn.json`: ```json { "deploy": { "migrations": { "enabled": "auto", "wait": true, "batchSize": 256, "pollIntervalMs": 1000, "timeoutMs": 900000, "strict": true, "allowDrift": false } } } } } ``` `kitcn dev` uses relaxed defaults (`strict: false`, `allowDrift: true`). ## Drift Safety Applied migrations are immutable. Two drift checks: | Drift | Cause | Effect | |-------|-------|--------| | Checksum mismatch | Applied migration file edited | Blocks next run | | Missing from manifest | Applied migration deleted | Blocks next run | `allowDrift` is emergency-only. Create new migrations for follow-up behavior. ## Internal Tables - `migration_state` — applied checksums and progress per migration - `migration_run` — run lifecycle (start, status, failures) Reserved names — do not create tables with these names. ## Runtime Statuses `pending``running``completed` | `failed` | `canceled` | `dry_run` | `noop` | `drift_blocked` ## Best Practices 1. **One migration per schema change** — don't bundle unrelated backfills. 2. **Codegen before migrate up** — deterministic order prevents stale function code. 3. **`safe_bypass` by default** — bypasses ORM rules/triggers for speed. Set `writeMode: 'normal'` when you need hooks. 4. **Don't edit applied migrations** — triggers checksum drift. Create new migration instead. 5. **Prefer code defaults** — `doc.field ?? 'default'` over migration when backward-compatible. ## Common Workflow: Optional → Required 1. `migrate create backfill_field` 2. Implement `migrateOne` to fill missing values 3. `codegen` then `migrate up` 4. Harden schema (`.notNull()`) 5. `codegen` to confirm ## Related References - ORM: `./orm.md` - Triggers: docs at `/docs/orm/schema/triggers` - CLI Backend: docs at `/docs/cli/backend`