Write Safe Migrations
Safe migrations are boring, repeatable, and tested against real old data.
Workflow
- Add the new schema version.
- Write the migration in one transaction when the platform allows it.
- Preserve data before dropping or rewriting columns.
- Add fixture data for the old version.
- Test old version to latest, not just previous to current.
- Run integrity and foreign key checks.
- Take a backup before migrating high-value data.
Room Checklist
@Database(
entities = [TransactionEntity::class],
version = 3,
exportSchema = true
)
abstract class AppDatabase : RoomDatabase()
- keep exported schemas in version control
- avoid using app constants inside migration SQL because old constants drift
- test data preservation, not only schema validation
- use destructive migration only for cache/prototype data
SQLite Checklist
BEGIN IMMEDIATE;
ALTER TABLE notes ADD COLUMN archived INTEGER NOT NULL DEFAULT 0;
PRAGMA foreign_key_check;
UPDATE app_meta SET value = '3' WHERE key = 'schema_version';
COMMIT;
- set or read
PRAGMA user_versionor app metadata - prefer additive changes when possible
- rebuild derived indexes after migration
- run
quick_checkorintegrity_checkafter risky migrations
IndexedDB Checklist
- open an old-version DB fixture in the browser
- perform the version upgrade
- assert object counts and transformed fields
- test blocked upgrades with two tabs open
- keep readers backward-compatible during gradual deploys