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/better-auth is a Better Auth adapter for schema generation — not a database driver. It lets Better Auth own its auth table definitions while sqlfu remains the migration owner for your project. Better Auth writes into a managed region of definitions.sql; sqlfu then diffs, drafts, and applies migrations the normal way.

What it solves

Better Auth needs to manage its own schema. Without this adapter, you would have to manually copy Better Auth’s table definitions into definitions.sql and keep them in sync whenever the Better Auth config changes. sqlfuBetterAuthAdapter handles that synchronization: auth generate writes directly into the right file, and sqlfu picks up the change on the next sqlfu draft.

Setup

1

Configure Better Auth

Use sqlfuBetterAuthAdapter in your Better Auth config:
auth.ts
import {betterAuth} from 'better-auth';
import {sqlfuBetterAuthAdapter} from 'sqlfu/better-auth';

export const auth = betterAuth({
  database: sqlfuBetterAuthAdapter(),
});
sqlfuBetterAuthAdapter() with no arguments resolves sqlfu.config.* from the current working directory. The configured definitions file is the only file it will write.
2

Configure sqlfu

A standard sqlfu config works without any special changes:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';

export default defineConfig({
  definitions: './definitions.sql',
  migrations: {path: './migrations'},
  queries: './sql',
});
3

Generate, draft, and migrate

Run these three commands on first setup and whenever the Better Auth config changes:
npx auth@latest generate --yes
npx sqlfu draft
npx sqlfu migrate
auth generate writes the auth schema into the managed region of definitions.sql. sqlfu draft compares the updated desired schema with migration history and writes a new migration file. sqlfu migrate applies it to the database.

How it works with definitions.sql

The adapter writes one managed region inside definitions.sql:
definitions.sql
-- #region sqlfu:better-auth
-- generated by Better Auth through sqlfuBetterAuthAdapter; edit Better Auth config instead
create table "user" (
  "id" text not null primary key,
  "name" text not null,
  "email" text not null unique,
  "emailVerified" integer not null,
  "image" text,
  "createdAt" date not null,
  "updatedAt" date not null
);
-- #endregion sqlfu:better-auth
Generated SQL is formatted with sqlfu’s formatter. SQL outside the managed region is preserved byte-for-byte. On the first run with an existing definitions.sql that has no managed region, the adapter appends the region if the combined application schema plus Better Auth schema applies cleanly to a scratch SQLite database. If your app already has a table that conflicts with Better Auth (for example, an app-owned "user" table), the adapter fails instead of guessing which schema should win. After the first run, subsequent auth generate calls replace the existing managed region in place. Plugin changes, extra user fields, and removed auth tables all flow through the same block.
You do not need to add the #region markers by hand for a normal first run. The adapter handles that automatically.

Runtime adapter delegation

Calling sqlfuBetterAuthAdapter() with no arguments is for schema generation only. Runtime create/read/update/delete methods throw with a message telling you to pass an underlying Better Auth adapter. If you want one Better Auth config to handle both generation and runtime, pass an adapter factory and sqlfu delegates runtime methods to it:
auth.ts
import {betterAuth} from 'better-auth';
import {kyselyAdapter} from 'better-auth/adapters/kysely';
import {sqlfuBetterAuthAdapter} from 'sqlfu/better-auth';

export const auth = betterAuth({
  database: sqlfuBetterAuthAdapter({
    adapter: kyselyAdapter(db, {type: 'sqlite'}),
  }),
});
If your production setup already uses Better Auth’s direct D1 support or another runtime path, keep that config and use a small CLI-only auth config for generation.

Troubleshooting

auth generate says the output file is wrong. The adapter only writes sqlfuConfig.definitions. Run without --output, or pass the path of the configured definitions file. First-time append fails. The combined desired schema did not apply to a scratch SQLite database. Common causes: an app-owned auth table name conflicts, a syntax error in the existing definitions.sql, or application DDL that depends on objects not defined in the file. auth generate returns no changes. If the managed Better Auth region is already up to date, the adapter returns an empty code body to the Better Auth CLI — this is expected behavior.

Migration model

How sqlfu tracks schema history and what each command mutates.

Getting started

The base SQL → draft → generate workflow.

Build docs developers (and LLMs) love