new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · Concepts · all subjects

database

31 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Database adapters and connection

Better Auth connects to a database to store data such as users, sessions, and more. You pass a supported database instance in the database options. Plugins can also define their own database tables to store data.

Better Auth works without a database using stateless sessions

Better Auth can operate without any database by using stateless session management. See the Stateless Session Management documentation for details.

Programmatic migrations with getMigrations

In environments where the CLI isn't available (e.g. Cloudflare Workers, serverless functions), you can run migrations programmatically using getMigrations from 'better-auth/db/migration'. This allows you to call getMigrations(auth.options) to get toBeCreated, toBeAdded, and runMigrations objects, then execute runMigrations() to apply them.

getMigrations only works with built-in Kysely adapter

getMigrations only works with the built-in Kysely adapter (SQLite/D1, PostgreSQL, MySQL, MSSQL). It does not work with Prisma or Drizzle ORM adapters—use CLI migrations with those ORMs instead.

Secondary storage for session and auth data

Secondary storage in Better Auth allows you to use key-value stores for managing session data, verification records, rate limiting counters, and other short-lived auth data. This can offload storage of intensive records to a high performance storage or RAM.

SecondaryStorage interface implementation

To use secondary storage, implement the SecondaryStorage interface with three methods: get(key: string) => Promise<unknown>, set(key: string, value: string, ttl?: number) => Promise<void>, and delete(key: string) => Promise<void>. Then provide your implementation to the betterAuth function in the secondaryStorage option.

Redis storage with ioredis package

Better Auth provides an official Redis storage package @better-auth/redis-storage that uses ioredis. Install with: npm install @better-auth/redis-storage ioredis. Import redisStorage from '@better-auth/redis-storage' and pass it to betterAuth secondaryStorage option with client and optional keyPrefix parameters.

Customizing table and column names

You can customize table names and column names for the core schema using modelName and fields properties in the auth config. For example, set user.modelName to 'users' and user.fields.name to 'full_name'. Type inference in your code will still use the original field names (e.g., user.name, not user.full_name).

Customizing plugin schema table and column names

To customize table names and column names for plugins, use the schema property in the plugin config with nested user or other model objects containing fields mappings.

Extending core schema with additionalFields

Better Auth provides a type-safe way to extend user and session schemas. Use additionalFields property with field names as keys and FieldAttributes objects as values. Each FieldAttributes object contains: type (data type), required (boolean), defaultValue (default value), input (whether Better Auth accepts field on create/update, default true), and returned (whether Better Auth includes field in responses, default true).

additionalFields input and returned behavior

For user.additionalFields, input and returned are independent: input true/returned true: API input and provider mapping can supply the field, stored field is included; input true/returned false: API input and provider mapping can supply field, stored field is omitted; input false/returned true: API input and provider mapping cannot supply field (use defaultValue or database write), stored field is included; input false/returned false: API input and provider mapping cannot supply field, stored field is omitted.

Example: Extending user schema with role and lang fields

```ts import { betterAuth } from "better-auth"; export const auth = betterAuth({ user: { additionalFields: { role: { type: ["user", "admin"], required: false, defaultValue: "user", input: false, }, lang: { type: "string", required: false, defaultValue: "en", }, }, }, }); ``` Then access additional fields like res.user.role and res.user.lang.

ID generation: Let database generate IDs

Set advanced.database.generateId to false to let your database handle all ID generation. Use generateId: 'serial' for auto-incrementing numeric IDs.

ID generation: Custom ID generation function

Use a function for generateId to generate IDs. Return false or undefined from the function to let the database generate ID for specific models. Setting generateId: false (without a function) disables ID generation for all tables.

Numeric IDs with serial

Set advanced.database.generateId to 'serial' to use auto-incrementing numeric IDs. This disables Better Auth ID generation for any table and assumes your database generates numeric IDs automatically. The CLI will generate the id field as a numeric type with auto-incrementing attributes.

UUID ID generation

Set advanced.database.generateId to 'uuid' to use UUIDs for the id field. By default, Better Auth generates UUIDs for all tables except PostgreSQL adapters where the database generates UUIDs automatically. The CLI will generate the id field as a UUID type.

Mixed ID types across tables

Use a generateId callback function to have different ID types across tables. For example, return false for user/users model to let PostgreSQL serial generate integer IDs, and return crypto.randomUUID() for other models like session, account, verification to generate UUIDs.

Plugins schema tables and columns

Plugins can define their own tables in the database to store additional data. They can also add columns to core tables. For example, the two factor authentication plugin adds twoFactorEnabled, twoFactorSecret, and twoFactorBackupCodes columns to the user table.

Adding plugin tables and columns

To add new tables and columns to your database for plugins, use either the CLI (migrate or generate command which scans your database and guides you through adding missing tables or columns) or the manual method by following instructions in the plugin documentation.

Experimental database joins support

Since Better Auth version 1.4, experimental database joins support allows Better Auth to perform multiple database queries in a single request, reducing database roundtrips. Over 50 endpoints support joins. The adapter system supports joins natively, so it will fallback to making multiple queries and combining results if joins are not enabled.

Enabling experimental database joins

To enable joins, update your auth config with experimental.joins set to true. The Better Auth 1.4 CLI will generate DrizzleORM and PrismaORM relationships, so update your schema by running migrate or generate CLI commands.

Session expiration default and refresh

Sessions expire after 7 days by default. Whenever a session is used and the updateAge is reached, the session expiration is updated to the current time plus the expiresIn value. The default expiresIn is 60 * 60 * 24 * 7 (7 days) and default updateAge is 60 * 60 * 24 (1 day).

Disable session refresh configuration

Session refresh can be disabled by setting disableSessionRefresh: true in the session configuration. When disabled, the session is not updated regardless of the updateAge option.

Defer session refresh for read replicas

When deferSessionRefresh: true is enabled, GET /get-session becomes read-only and returns needsRefresh: true when refresh is needed. The client automatically calls POST to perform the refresh. This solves issues with read-replica database setups where GET requests are routed to read-only replicas.

Session freshness concept

A session is considered fresh if its createdAt is within the freshAge limit. Some endpoints in Better Auth require the session to be fresh. The default freshAge is 1 day (60 * 60 * 24 seconds). Setting freshAge to 0 disables the freshness check.

Session revocation in secondary storage

By default, if a secondary storage is provided in the auth configuration, sessions are stored in the secondary storage instead of the database. You can choose to store sessions in the database instead by passing storeSessionInDatabase: true in the session configuration.

Preserve revoked sessions in database

When preserveSessionInDatabase: true is enabled in the session configuration with secondary storage, revoked sessions will be preserved in the database and not deleted. This is useful to keep track of sessions that have been revoked.

Stateless session management overview

Better Auth supports stateless session management without any database. Session data is stored in a signed or encrypted cookie and the server verifies the cookie signature and checks expiration instead of querying a database. If no database configuration is passed, Better Auth automatically enables stateless mode.

Manual stateless mode configuration

To manually enable stateless mode, configure cookieCache with enabled: true and maxAge, and set account.storeStateStrategy to 'cookie' and account.storeAccountCookie to true. The cookieCache.strategy can be 'jwe', 'jwt', or 'compact', and refreshCache: true enables stateless refresh.

storeAccountCookie stores OAuth token material

storeAccountCookie stores provider account data, including OAuth token material, in the encrypted account_data cookie. getAccessToken can refresh expired provider access tokens when the account cookie contains a refresh token and a known access-token expiry. Token refresh responses set an updated account cookie, so server-side integrations must forward the returned Set-Cookie header to the browser.

Stateless sessions with secondary storage combination

Better Auth supports combining stateless sessions with secondary storage (Redis, etc.) for the best of both worlds. This setup uses cookies for session validation (no DB queries) and uses secondary storage for storing session data and refreshing the cookie cache before expiry. Sessions can be revoked from secondary storage and the cookie cache will be invalidated on refresh.

Give your agent this brain