Better Auth database
Better Auth’s built-in database layer is Kysely, and any Kysely dialect plugs
into it. @persql/kysely is that dialect for PerSQL, so an app’s users,
sessions, and accounts can live in their own isolated SQLite database — one per
app, or one per tenant.
npm install better-auth @persql/kysely @persql/sdkimport { betterAuth } from "better-auth";import { PerSQL } from "@persql/sdk";import { PerSQLDialect } from "@persql/kysely";
const client = new PerSQL({ token: process.env.PERSQL_TOKEN });
export const auth = betterAuth({ database: { dialect: new PerSQLDialect({ database: client.database("acme/auth") }), type: "sqlite", }, emailAndPassword: { enabled: true },});Migrations
Section titled “Migrations”Better Auth generates its schema through the same dialect. Run the migration step once at deploy time (or whenever you add plugins that bring tables):
import { getMigrations } from "better-auth/db/migration";
const { runMigrations } = await getMigrations(auth.options);await runMigrations();This creates the user, session, account, and verification tables in the
PerSQL database, plus whatever your enabled plugins need.
Auth data is rows
Section titled “Auth data is rows”The auth database is a normal PerSQL database: inspect sign-ups from the console, expose a read-only endpoint over it, or answer operational questions with SQL:
SELECT date(createdAt) AS day, COUNT(*) AS signupsFROM user GROUP BY 1 ORDER BY 1 DESC LIMIT 14;One auth database per tenant
Section titled “One auth database per tenant”For multi-tenant products, mint a database per tenant and point each tenant’s
betterAuth instance at its own: tenant data never shares tables, deleting a
tenant is deleting a database, and each tenant’s auth spend is metered against
its own namespace.