{"protocol":"clank-doc/1","frameworkVersion":"0.8.0","slug":"migrations","title":"SQLite migrations","description":"Framework document tables and indexes can still be created automatically. Deployment migrations cover relational support tables, columns, constraints, indexes, and SQL data changes.","group":{"id":"full-stack","title":"Full stack"},"url":"https://docs.clank.run/docs/migrations","source":"docs/migrations.md","headings":["Files and ledger","Transactions and safety","Backup and failure","Expand and contract","Data restore","Local checks"],"tableOfContents":[{"id":"files-and-ledger","title":"Files and ledger","level":2},{"id":"transactions-and-safety","title":"Transactions and safety","level":2},{"id":"backup-and-failure","title":"Backup and failure","level":2},{"id":"expand-and-contract","title":"Expand and contract","level":2},{"id":"data-restore","title":"Data restore","level":2},{"id":"local-checks","title":"Local checks","level":2}],"markdown":"# SQLite migrations\n\nFramework document tables and indexes can still be created automatically. Deployment migrations cover relational support tables, columns, constraints, indexes, and SQL data changes.\n\n## Files and ledger\n\n```text\nmigrations/\n  0001_create_accounts.sql\n  0002_add_account_status.sql\n```\n\nNames match `<4-12 digits>_<lowercase-name>.sql`; IDs strictly increase.\n\nClank records:\n\n```sql\nCREATE TABLE clank_migrations (\n  id TEXT PRIMARY KEY,\n  name TEXT NOT NULL,\n  checksum TEXT NOT NULL,\n  applied_at INTEGER NOT NULL\n);\n```\n\nThe checksum covers exact SQL bytes. Editing, renaming, or removing applied history stops deployment. Fix production with a new migration.\n\n## Transactions and safety\n\nAll pending migrations run in one `BEGIN IMMEDIATE`. Either every migration and ledger row commits, or none does.\n\nDefaults reject:\n\n- `ATTACH`, `DETACH`, and `VACUUM`;\n- `load_extension`;\n- all `PRAGMA` statements;\n- top-level `BEGIN`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`, and `RELEASE`.\n- references to reserved `clank_` and legacy `proact_` SQL tables.\n\nExtension loading is disabled, foreign keys and `trusted_schema=OFF` are enforced, durability is `FULL`, and integrity plus foreign-key checks run before and after migration.\n\n`allowUnsafeMigrations: true` is only a request. The platform operator must also set `CLANK_ALLOW_UNSAFE_MIGRATIONS=1`; otherwise deployment is rejected. Enabling it lets migration SQL execute with control-plane filesystem authority and is inappropriate for untrusted deployers.\n\n## Backup and failure\n\nBefore migration, Clank stops the active app and uses Node's SQLite backup API. Backup and restore reject symbolic links, verify source and destination integrity, keep files private, and replace through a verified temporary file. On migration, startup, or health failure Clank stops the candidate, restores the snapshot, and restarts the prior release.\n\nSame-disk snapshots do not protect against disk loss. Export encrypted backups off-host and test restoration.\n\n## Expand and contract\n\nFor code-only rollback:\n\n1. Add compatible nullable structures.\n2. Deploy code that reads old/new and writes new.\n3. Backfill.\n4. Depend on the new form.\n5. Remove the old form after the rollback window.\n\nAvoid dropping a required column in the same release that first stops using it.\n\n## Data restore\n\nSnapshot restore discards newer writes. It is available only to the immediately previous release and requires an exact project confirmation.\n\n## Local checks\n\n```sh\nclank migrate plan\nclank migrate apply\n```\n\nLarge online backfills should be application jobs rather than one long deployment transaction. JavaScript migration files are intentionally unsupported. External PostgreSQL uses the structured HTTPS driver and immutable transactional ledger described in [Managed ingress and external data](data-plane.md).\n"}