Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iterate/sqlfu/llms.txt

Use this file to discover all available pages before exploring further.

sqlfu treats schema history as an explicit sequence of reviewed SQL files. You edit definitions.sql to declare what you want the schema to look like, then run sqlfu draft to produce the migration that gets you there. The diff engine, migration history table, and live schema form a chain of four named authorities that every command respects.
tl;dr: just run sqlfu check — it says “all good” or gives you the recommended next action.

The four authorities

Every sqlfu command operates on one or more of these four sources of truth. Understanding which authority each command reads from — and which it mutates — makes the whole model predictable.
AuthorityMeaningRepresentation
Desired SchemaThe schema the application wants nowdefinitions.sql
MigrationsThe ordered transition programmigrations/*.sql
Migration HistoryWhat a specific database claims it has appliedsqlfu_migrations table
Live SchemaWhat the database actually looks like right nowInspected directly from the database
The model is mostly a chain: Desired Schema determines what Migrations should produce; Migrations determine what Migration History may contain; Migration History determines what the Live Schema should look like.

Authority mismatches

When two authorities disagree, sqlfu gives the disagreement a name. Each name has a distinct meaning and a recommended next action.
NameComparisonLikely action
Repo DriftDesired Schema ≠ Migrationssqlfu draft
Pending MigrationsMigrations ahead of Migration Historysqlfu migrate
History DriftApplied migrations no longer match the repoFix the repo first, or reconcile with sqlfu baseline + sqlfu goto
Schema DriftLive Schema ≠ what Migration History impliessqlfu baseline <target> or sqlfu goto <target>
Sync DriftLive Schema ≠ Desired SchemaDepends on other mismatches
History Drift is the most serious: it means a database claims to have applied migrations that no longer match the known migration set. It may not have a single safe automatic fix. The two most common causes are editing an old migration after it was applied, or pushing a database forward with repeated sqlfu sync calls that bypass the history chain.

Migration workflow

1

Edit definitions.sql

Change table definitions, add columns, create indexes. This is the only file you author directly. It represents the schema you want the application to have.
2

Draft a migration

sqlfu draft
The diff engine replays the existing migrations, compares the result to definitions.sql, and writes a new migration file into migrations/. The file is named with an ISO timestamp prefix by default (e.g. 2026-04-22T10.30.45.123Z_add_published_to_posts.sql).
3

Review the migration

Open the generated file. The diff engine makes a best effort, but renames, destructive changes, and backfills are product decisions — review the SQL before applying it.
4

Apply the migration

sqlfu migrate
Applies pending migrations to the database and records each one in sqlfu_migrations. No row is written for a failed migration.

What each command mutates

Understanding mutation boundaries makes it safe to reach for the right command under pressure.

sqlfu draft

Reads Migrations, replays them, compares the result to the Desired Schema, and writes a new migration file. Mutates: Migrations Does not touch: Migration History, Live Schema

sqlfu migrate

Applies pending migrations to the database and records them. Mutates: Migration History, Live Schema Does not touch: Desired Schema, Migrations

sqlfu baseline <target>

Declares that this database should be treated as having applied migrations through <target>, without changing the actual schema. Mutates: Migration History Does not touch: Desired Schema, Migrations, Live Schema

sqlfu goto <target>

Makes the database look like the schema implied by migrations through <target> and records that history. Mutates: Migration History, Live Schema Does not touch: Desired Schema, Migrations
sqlfu goto is more powerful and more dangerous than sqlfu migrate. It rewrites both schema and history to match a specific migration prefix, discarding whatever the database had before.

sqlfu sync

Updates the Live Schema directly from the Desired Schema, skipping the migration chain entirely. Mutates: Live Schema Does not touch: Migrations, Migration History After sync, the database may be schema-current but history-dirty. It is useful for local development but is not a history-preserving command.

sqlfu check

Mutates nothing. Verifies all four authority relationships and recommends the least-destructive next step it can justify from the evidence.

sqlfu check recommendations

sqlfu check matches named mismatch types to specific recommendations rather than generic failure text.
  • Repo Drift only — recommend sqlfu draft
  • Pending Migrations only — recommend sqlfu migrate
  • Schema Drift only — recommend sqlfu baseline <target> or sqlfu goto <target>. If check can prove the Live Schema matches a replayed migration prefix exactly, it recommends that specific target.
  • Pending Migrations + Sync Drift — recommend sqlfu migrate; the Sync Drift recommendation defers to that same step
  • Repo Drift + Sync Drift — recommend sqlfu draft; the repo needs a migration before the database can become migration-current honestly
  • History Drift only — no single automatic recommendation. check explains the likely causes and offers two paths: fix the repo if old migrations were edited, or reconcile deliberately with sqlfu baseline + sqlfu goto
  • Multiple mismatches — prefer the most upstream mismatch first: Repo Drift → History Drift → Pending Migrations → Schema Drift → Sync Drift

Migration presets

sqlfu tracks applied migrations in a bookkeeping table. Two presets are available:
PresetTableChecksum trackingDefault prefix
'sqlfu' (default)sqlfu_migrationsYesiso
'd1'd1_migrationsNofour-digit
The 'd1' preset makes sqlfu read and write the same d1_migrations table that Cloudflare’s alchemy and wrangler tools manage. Under this preset, sqlfu cannot detect that an already-applied migration’s content was edited after the fact — there is no checksum column. This is a deliberate tradeoff for alchemy compatibility.
sqlfu.config.ts
export default defineConfig({
  db: async () => /* your D1 / miniflare client factory */,
  migrations: {path: 'migrations', preset: 'd1'},
  definitions: 'definitions.sql',
  queries: 'sql',
});

Migration naming and prefix options

Migration files are ordered lexicographically by filename, so the prefix must be sortable. Two formats are supported:
  • iso (default) — ISO timestamp prefix: 2026-04-22T10.30.45.123Z_create_people.sql
  • four-digit — Sequential integer prefix: 0000_create_people.sql, 0001_add_index.sql
The four-digit format matches conventions used by pgkit, Kysely, Prisma, and similar tools. Enable it by passing migrations as an object:
sqlfu.config.ts
export default defineConfig({
  migrations: {path: './migrations', prefix: 'four-digit'},
});
Do not mix prefix formats in the same directory. Lexicographic ordering between an ISO timestamp and a four-digit number is not coherent.
The prefix field is defaulted from the preset but can be overridden explicitly. For example, {preset: 'd1', prefix: 'iso'} is valid if you want alchemy’s table with ISO-prefixed filenames.

Failed migrations

When a migration fails, the key question is not “did a migration fail?” but “is this database still honest about what it has applied?” sqlfu_migrations records success only. A row is written only after a migration’s SQL finishes successfully. There is no “failed” row and no failure-status column. This keeps the meaning of Migration History stable. Preflight check. Before applying anything, sqlfu migrate checks that the database’s Live Schema still matches what its recorded Migration History implies. If History Drift or Schema Drift is present, migrate refuses to proceed and points at the reconciliation steps required. Post-failure health check. When a migration execution fails, sqlfu migrate reruns a health check against the post-failure state:
  • If the migration rolled back cleanly, the error message says the database is still healthy for migrate. Fix the migration and run sqlfu migrate again.
  • If the migration left the Live Schema out of sync with Migration History, the error says reconciliation is required and shows the same recommendation-style diagnostics as sqlfu check.
sqlfu does not invent a special repair command for failed migrations. It reuses sqlfu goto and sqlfu baseline — the same tools the four-authority model already has.

Durable Objects migration pattern

Cloudflare Durable Objects make the chain visible because each object instance has its own private SQLite database. On startup, each object must reconcile its private database with the migrations bundled into the deployed Worker code.
1

Edit definitions.sql and draft migrations

Edit definitions.sql, run sqlfu draft, and commit the generated migrations/*.sql files as part of the Worker bundle.
2

Generate a TypeScript migrations bundle

sqlfu generate
This writes migrations/.generated/migrations.ts — a plain TypeScript bundle containing the migration files. Commit this alongside your migration SQL files.
3

Run migrations in the Durable Object constructor

import {createDurableObjectClient} from 'sqlfu';
import {migrate} from './migrations/.generated/migrations.ts';

export class MyObject {
  constructor(ctx: DurableObjectState, env: Env) {
    const client = createDurableObjectClient(ctx.storage);
    migrate(client);
  }
}
Pass the full ctx.storage object, not ctx.storage.sql, so sqlfu can use Durable Objects’ transactionSync() API for per-migration rollback.
Missing migrations are treated as an integrity problem: if a Durable Object database has sqlfu_migrations rows not present in the generated bundle, applyMigrations() fails before applying newer migrations. Under the default sqlfu preset it also checks applied migration checksums, so editing an already-applied migration file is reported as history drift.
sqlfu draft and sqlfu check are pre-deployment tools. Do not use the diff engine as runtime magic inside a Durable Object to synthesize missing migrations at startup — runtime schema changes still need reviewable migration files.

Runtime migration API

For environments where you bundle migrations at build time — primarily Cloudflare Durable Objects — sqlfu exports two functions from the main package:
  • applyMigrations(client, params) — applies a set of migrations to the client. Accepts both SyncClient and AsyncClient and returns a matching sync or async result. The params object includes migrations, preset, and prefix options.
  • migrationsFromBundle(bundle) — converts the generated MigrationBundle (from migrations/.generated/migrations.ts) into the Migration[] array that applyMigrations consumes.
In practice, the generated migrate function exported from migrations/.generated/migrations.ts wraps both calls for you, so most projects never call these functions directly. They are exported for custom migration runners or for testing against explicit migration sets.
import {applyMigrations, migrationsFromBundle} from 'sqlfu';
import bundle from './migrations/.generated/migrations.ts';

const migrations = migrationsFromBundle(bundle);
await applyMigrations(asyncClient, {migrations});

Build docs developers (and LLMs) love