Preview and apply
const transform = (data: Database["todos"]) => ({ ...data, title: data.title.trim() });
const preview = await db.migrations.run("todos", transform, { dryRun: true });
const applied = await db.migrations.run("todos", transform);
// Specify the old type when it differs from the destination schema.
await db.migrations.run<"todos", { text: string; done?: boolean }>(
"todos",
old => ({ title: old.text, done: old.done ?? false }),
{ dryRun: true },
);
Migrations read the active author’s public records, including legacy data that fails the destination schema. All transformed records are validated before the first write. Return null to skip a record. Applying a migration upserts the full object, removes obsolete fields, preserves IDs and original creation times, and requests a signature for each changed record. The initial author remains fixed if the active account changes.
Options include signal and queue. A queued migration uses local records and saves signed writes for explicit replay. Migrations are not atomic. data.rows, data.receipts, and meta.receipts preserve completed work after partial failure. There is no relay-wide schema change or multi-author migration authority.