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.config.ts is the single file that tells sqlfu where your database is, where your migrations live, where your query files are, and how to generate TypeScript wrappers. It lives at your project root and is picked up automatically by every sqlfu command.
sqlfu.config.ts
import {defineConfig} from 'sqlfu';

export default defineConfig({
  db: './db/app.sqlite',
  migrations: './migrations',
  definitions: './definitions.sql',
  queries: './sql',
});
Use defineConfig to get type checking and editor autocomplete on the config object. Passing a plain object literal works too, but defineConfig is preferred.

Required fields

definitions
string
required
Path to your schema source of truth — the definitions.sql file that describes the schema you want right now. sqlfu reads this when drafting migrations and (by default) when generating types. Relative paths are resolved from the config file’s directory.
queries
string
required
Path to the directory containing your checked-in .sql query files. sqlfu generate reads every .sql file here and emits typed wrappers into a .generated/ subdirectory alongside them. Relative paths are resolved from the config file’s directory.

Optional fields

db
string | () => Promise<DisposableAsyncClient>
The database sqlfu talks to for migrate, check, sync, goto, baseline, the Admin UI, and generate when its authority needs a live DB.
  • String path — opens a local SQLite file. Example: './db/app.sqlite'.
  • Factory function — returns a DisposableAsyncClient. Use this for Cloudflare D1, Turso, or any adapter-mediated database (see Pluggable db below).
  • Omitted — commands that need a database fall back to .sqlfu/app.db, a local scratch file. Useful while authoring migrations and types before wiring a runtime database.
migrations
string | object
Path to the directory containing your migration files, or a config object:
migrations: {
  path: './migrations',      // required
  prefix: 'iso',             // 'iso' (default) or 'four-digit'
  preset: 'sqlfu',           // 'sqlfu' (default) or 'd1'
}
Omit this field entirely for library-author projects that do not use migrations.Set preset: 'd1' for Cloudflare D1 projects already using alchemy or wrangler — sqlfu will read and write the same d1_migrations table those tools use. The four-digit prefix matches wrangler’s filename format.
generate.authority
string
default:"desired_schema"
Controls where sqlfu generate reads the schema from when producing typed wrappers. See generate.authority below for all four options.
generate.validator
string | null
Opt into runtime validation baked into generated wrappers. Accepts 'arktype', 'valibot', 'zod', 'zod-mini', or null (the default, no validation). When set, wrappers validate params on the way in and rows on the way out, and derive types via the validator’s native inference. See Runtime validation.
generate.experimentalJsonTypes
boolean
default:"false"
Opt into experimental JSON logical-type handling. Today this covers SQLite columns declared exactly as json; the same flag is reserved for typed JSON metadata and schema support as it evolves.
generate.runtime
string
default:"sqlfu"
Controls the code generation target. Accepts 'sqlfu' (default), 'effect-v3', or 'effect-v4-unstable'. Set to 'effect-v3' to emit wrappers that return Effect values and integrate with Effect SQL’s SqlClient. The Effect v4 beta target is experimental. See Type generation.
generate.prettyErrors
boolean
default:"true"
When true (the default), validation failures from the configured generate.validator throw with a human-readable error message. Set to false to let the raw error from the underlying validator library pass through untouched. Has no effect when generate.validator is null.
generate.sync
boolean
default:"false"
When true, generated wrappers accept a SyncClient and return values directly (no async/await, no Promise<...> return types). Use this when your project always runs against a synchronous driver (node:sqlite, better-sqlite3, bun:sqlite). The resulting wrappers are easier to call from non-async contexts such as constructors.
generate.importExtension
string
default:".js"
The file extension used in generated import statements. Accepts '.js' or '.ts'. Defaults to '.js' unless your tsconfig.json sets verbatimModuleSyntax or rewriteRelativeImportExtensions, in which case sqlfu infers '.ts'.

generate.authority

sqlfu generate needs to know your schema to produce typed query wrappers. The generate.authority option controls where it reads the schema from:
generate.authority
string
default:"desired_schema"
One of four values:
  • 'desired_schema' (default) — reads definitions.sql directly. No database required. Fastest and most deterministic. Drift between definitions.sql and migrations is surfaced by sqlfu check, not silently hidden.
  • 'migrations' — replays migrations/*.sql into a scratch database and extracts the resulting schema. No database required. Types follow what the migrator would actually produce.
  • 'migration_history' — reads sqlfu_migrations from config.db, then replays the matching migration files. Requires a configured db. Throws if a recorded migration is missing from migrations/. Use when types should match what is actually deployed.
  • 'live_schema' — extracts schema directly from config.db. Requires db to be populated up-front. Use when you want types to follow the live database regardless of migration history.
sqlfu.config.ts
import {defineConfig} from 'sqlfu';

export default defineConfig({
  definitions: './definitions.sql',
  queries: './sql',
  migrations: './migrations',
  generate: {authority: 'migrations'},
});
desired_schema is the right choice for most projects. Switch to migrations or migration_history when you want generated types to precisely track what the migrator produces rather than what definitions.sql declares.

Pluggable db

When your app talks to an adapter-mediated database (Cloudflare D1, Turso, libsql, a Miniflare binding), point sqlfu at the same client your app uses by giving db a factory function instead of a path. Every sqlfu command that touches the database will then operate on the real database, not a scratch file.
sqlfu.config.ts
import {defineConfig, createD1Client} from 'sqlfu';
import {Miniflare} from 'miniflare';

export default defineConfig({
  db: async () => {
    const mf = new Miniflare({
      script: '', modules: true,
      d1Persist: true,
      d1Databases: {DB: '<dev-db-id>'},
    });
    await mf.ready;
    const d1 = await mf.getD1Database('DB');
    return {
      client: createD1Client(d1),
      async [Symbol.asyncDispose]() { await mf.dispose(); },
    };
  },
  migrations: './migrations',
  definitions: './definitions.sql',
  queries: './sql',
});
The factory is invoked on every openDb call. sqlfu calls [Symbol.asyncDispose] when the command scope exits. Memoize inside the factory if setup is expensive (for example, spinning up Miniflare once per process). For Alchemy-managed local D1, sqlfu can talk directly to Alchemy’s persisted Miniflare sqlite file:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';
import {findMiniflareD1Path} from 'sqlfu/cloudflare';

export default defineConfig({
  db: findMiniflareD1Path('my-dev-app-slug'),
  migrations: {path: './src/server/db/migrations', preset: 'd1'},
  definitions: './src/server/db/definitions.sql',
  queries: './src/server/db/queries',
});
findMiniflareD1Path() walks up from process.cwd() until it finds a supported Miniflare v3 persist root and derives the D1 sqlite filename from the slug.

Multi-project pattern

If a repo has more than one sqlfu project (for example, multiple Durable Objects), pass the config file explicitly:
sqlfu --config ./durable-objects/counter/sqlfu.config.ts generate
sqlfu --config ./durable-objects/session/sqlfu.config.ts draft
Relative paths inside each config are resolved from the config file’s directory, so each project keeps its own definitions.sql, migrations/, and sql/ directories alongside its config.

The .sqlfu/ directory

sqlfu manages its own temporary files under .sqlfu/, including scratch databases used for schema diffing and the default app.db fallback when db is omitted. These files are generally safe to delete at any time. Add .sqlfu/ to your .gitignore.

dialect (advanced)

sqlfu ships with sqliteDialect as the default dialect, wired up automatically when defineConfig omits dialect. For projects that use the @sqlfu/pg package (PostgreSQL support), pass pgDialect from that package here. Custom dialect implementations are possible by implementing the Dialect interface exported from sqlfu.
import {defineConfig, sqliteDialect} from 'sqlfu';

export default defineConfig({
  // dialect: sqliteDialect(),  // this is the default; explicit is optional
  definitions: './definitions.sql',
  queries: './sql',
});
In practice, most projects never set dialect explicitly — the default SQLite dialect is used automatically.

Build docs developers (and LLMs) love