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 · all subjects

adapters

118 notes in this subject, read out of this brain and free to use. This is page 2 of 2.

Adapter factory config object - optional fields

The config object passed to createAdapterFactory can include the following optional fields: usePlural (boolean, whether table names in schema are plural, default false), debugLogs (boolean or object, whether to enable debug logs, default false), supportsJSON (boolean, whether database supports JSON, default false), supportsDates (boolean, whether database supports dates, default true), supportsBooleans (boolean, whether database supports booleans, default true), supportsNumericIds (boolean, whether database supports auto-incrementing numeric IDs, default true), supportsUUIDs (boolean, whether database natively generates UUIDs, default false), supportsArrays (boolean, whether database supports array columns, default false), transaction (boolean or function, whether adapter supports transactions), disableIdGeneration (boolean, whether to disable ID generation), customIdGenerator (function, custom ID generation logic), mapKeysTransformInput (object, maps old key names to new names for input), mapKeysTransformOutput (object, maps old key names to new names for output), customTransformInput (function, transforms input data before saving), customTransformOutput (function, transforms output data after retrieving), disableTransformInput (boolean, disable input transformation), disableTransformOutput (boolean, disable output transformation), disableTransformJoin (boolean, disable join transformation).

Adapter function parameters

The adapter function receives the following parameters: options (Better Auth options), schema (schema from user's Better Auth instance), debugLog (debug log function), getModelName (function to get transformed model name for database), getFieldName (function to get transformed field name for database), getDefaultModelName (function to get default model name from schema), getDefaultFieldName (function to get default field name from schema), getFieldAttributes (function to get field attributes for specific model and field), transformInput (function to transform input data before saving), transformOutput (function to transform output data after retrieving), transformWhereClause (function to transform where clauses for database queries).

Adapter create method

The create method inserts a new record into the database. Parameters: model (string, model/table name), data (object, data to insert), select (array of strings, fields to return). Returns Promise<T> with the inserted record. The create method can receive forceAllowId parameter which allows id to be provided in data object; this is handled internally and requires no special handling by the adapter.

Adapter update method

The update method updates a single record in the database. Parameters: model (string, model/table name), where (object, where clause to match record), update (object, data to update with). Returns Promise<T | null> with the updated row or null if no row matched. With multiple where clauses, some adapters cannot return the updated row.

Adapter updateMany method

The updateMany method updates multiple records in the database. Parameters: model (string, model/table name), where (object, where clause to match records), update (object, data to update with). Returns Promise<number> with the count of records updated.

Adapter delete method

The delete method deletes a single record from the database. Parameters: model (string, model/table name), where (object, where clause to match record). Returns Promise<void>.

Adapter deleteMany method

The deleteMany method deletes multiple records from the database. Parameters: model (string, model/table name), where (object, where clause to match records). Returns Promise<number> with the count of records deleted.

Adapter consumeOne method - optional atomic delete

The consumeOne method (optional) atomically deletes a single matching record and returns it, ensuring two concurrent requests cannot consume the same row. This powers single-use credentials like one-time verification challenges. Parameters: model (string, model/table name), where (object, where clause to match single record). Returns Promise<T | null> with the consumed record or null if no row matched. If omitted, the adapter factory falls back to wrapping findMany + deleteMany in a transaction. Implementing consumeOne natively is recommended over using the fallback, as the fallback is race-safe only under a real transaction with accurate delete count.

Adapter findOne method

The findOne method finds a single record in the database. Parameters: model (string, model/table name), where (object, where clause to match record), select (array of strings, fields to return), join (optional object, join configuration to fetch related records). Returns Promise<T | null> with the matching record or null if none found. The select parameter is only for query efficiency; the adapter factory handles filtering returned fields.

Adapter findMany method

The findMany method finds multiple records in the database. Parameters: model (string, model/table name), where (object, where clause to match records), limit (number, max records to return), select (array of strings, fields to return), sortBy (object, sort configuration), offset (number, record offset), join (optional object, join configuration to fetch related records). Returns Promise<T[]> with array of matching records. The select parameter is only for query efficiency; the adapter factory handles filtering returned fields.

Adapter count method

The count method counts the number of records in the database. Parameters: model (string, model/table name), where (object, where clause to match records). Returns Promise<number> with the count of records.

Adapter model name transformation

All model values passed to adapter methods are already transformed into the correct model name for the database based on end-user schema configuration. If access to the schema version of a model is needed, use the getDefaultModelName function to convert the model to its schema version.

Adapter automatic field completion

The adapter factory automatically fills in any missing fields in returned records based on user schema configuration. Adapter methods do not need to return all fields.

Adapter options object parameter

The options object in the adapter function is for configuration passed in through custom adapter options. It should be returned in the adapter's options property to make it available.

Testing adapters with test utils

Better Auth provides a test suite via the @better-auth/test-utils package for testing custom adapters. It requires vitest. Use testAdapter and createTestSuite functions from @better-auth/test-utils/adapter. The testAdapter function handles test lifecycle including running migrations before tests and cleaning up tables after tests complete.

supportsNumericIds config - numeric ID support

The supportsNumericIds config option indicates whether the database supports numeric IDs. If set to false and user's config has enabled useNumberId, an error will be thrown.

supportsUUIDs config - native UUID generation

The supportsUUIDs config option indicates whether the database can natively generate UUIDs. Default is false. Set to true if the database generates UUIDs itself.

supportsJSON config - JSON field support

The supportsJSON config option indicates whether the database supports JSON fields. If the database doesn't support JSON, the adapter factory will use a string to save JSON data and safely parse it back into a JSON object when retrieved.

supportsDates config - date field support

The supportsDates config option indicates whether the database supports date fields. Default is true. If the database doesn't support dates, the adapter factory will use an ISO string to save dates and safely parse it back into a Date object when retrieved.

supportsBooleans config - boolean field support

The supportsBooleans config option indicates whether the database supports boolean fields. Default is true. If the database doesn't support booleans, the adapter factory will use 0 or 1 to save boolean values and safely parse them back into boolean values when retrieved.

supportsArrays config - array field support

The supportsArrays config option indicates whether the database supports array columns. Default is false. If false, array fields (string[], number[]) are stored as a serialized string and safely parsed back when retrieved. Set to true if the database supports array columns natively.

usePlural config - table naming convention

The usePlural config option indicates whether table names in the schema are plural. This is often defined by the user and passed through custom adapter options. If not intending to allow user customization of table names, this can be ignored or set to false.

transaction config - transaction support

The transaction config option indicates whether the adapter supports transactions. If false, operations run sequentially. If true, provide a function that executes a callback with a TransactionAdapter. If database doesn't support transactions, error handling and rollback will not be as robust; databases with transaction support are recommended for better data integrity.

debugLogs config - adapter debug logging

The debugLogs config option enables debug logs for the adapter. Can be a boolean (true logs all methods) or an object with keys: create, update, updateMany, findOne, findMany, delete, deleteMany, count. If any key is true, debug logs are enabled for that method.

disableIdGeneration config - ID generation control

The disableIdGeneration config option disables ID generation. If set to true, the user's generateId option will be ignored.

customIdGenerator config - custom ID generation logic

The customIdGenerator config option allows providing custom ID generation logic when the database only supports a specific ID generation method.

mapKeysTransformOutput config - output key mapping

The mapKeysTransformOutput config option maps key names when retrieving from database. Each key in the object represents the old key name to replace, and the value represents the new key name. This is useful for databases with different key naming conventions, such as MongoDB using _id instead of id. The object can be partial, transforming only some keys. Example: { _id: 'id' } replaces _id (from MongoDB) with id (for Better-Auth) when retrieving.

customTransformInput config - input data transformation

The customTransformInput config option transforms input data before it is saved to the database. The function receives: data (the data to transform), field (field being transformed), fieldAttributes (field attributes), action (adapter action called: create or update), model (model being transformed), schema (schema being transformed), options (Better Auth options). The function runs at every key in the data object. If using supportsJSON, supportsDates, or supportsBooleans, transformations are applied before customTransformInput is called.

customTransformOutput config - output data transformation

The customTransformOutput config option transforms output data before it is returned to the user. Similar to customTransformInput, it runs at every key in the data object of a given action but after data is retrieved from the database.

disableTransformInput config - disable input transformation

The disableTransformInput config option disables input transformation. Should only be used if manually handling all transformations. Disabling input transformation can break important adapter functionality like ID generation, boolean/date/JSON conversion, and key mapping.

disableTransformOutput config - disable output transformation

The disableTransformOutput config option disables output transformation. Should only be used if manually handling all transformations. Disabling output transformation can break important adapter functionality like boolean/date/JSON parsing and key mapping.

disableTransformJoin config - disable join transformation

The disableTransformJoin config option disables join transformation. Should only be used if manually handling joins. Disabling join transformation can break join functionality.

Adapter factory adapter field auto-filling behavior

The adapter factory handles automatic field completion and you do not need to worry about returning only what the select parameter states, as the factory will handle field filtering. For any method with a select parameter, it is only for query efficiency purposes.

Example custom adapter implementation

A custom adapter is created by calling createAdapterFactory with a config object and adapter function. The config object includes adapterId, adapterName, and capability flags. The adapter function returns an object with methods: create, update, updateMany, delete, deleteMany, findOne, findMany, count. Example: export const myAdapter = (config) => createAdapterFactory({ config: { adapterId: 'custom', adapterName: 'Custom Adapter', ... }, adapter: ({ options, schema, debugLog, ... }) => { return { create: async ({ model, data, select }) => { ... }, ... }; } });

Database adapters must implement `incrementOne` and `consumeOne`

`incrementOne` updates one row's counter atomically and returns the row, or null when the guard did not match. `consumeOne` reads and deletes a row in one step for single-use credentials. Both are now required for custom database adapters, and the old fallback is gone. A missing `consumeOne` throws at runtime. All built-in adapters already implement both.

Secondary storage must implement `increment` and `getAndDelete`

`increment(key, ttl)` bumps a counter by one and sets the expiry only when the key is first created. `getAndDelete(key)` reads and removes a key in one step. Both are now required for custom secondary storage and were optional before. Redis storage already implements both.

Rate-limit storage uses single `consume` method

Rate-limit storage now needs a single `consume(key, rule)` method that checks and increments in one step. Separate `get` and `set` are no longer accepted. Replace `get` and `set` in custom rate-limit storage with `consume`.

Drizzle schema uses singular relation keys with `usePlural`

The Drizzle schema generator now emits singular keys for many-to-one relations. This changes output only for projects configured with `usePlural: true`; the default singular configuration is unaffected, and reverse "many" relation keys are unchanged. If you set `usePlural: true`, regenerate your Drizzle schema and review the relation keys.

Better Auth Verification table schema

The Better Auth 'verification' table has the following fields: id (string, primary key), identifier (string), value (string), expiresAt (Date), createdAt (Date), updatedAt (Date).

User table schema differences from Auth.js

In Better Auth compared to Auth.js: name, email, and emailVerified are required (not optional); emailVerified is a boolean instead of a Date timestamp; Better Auth includes createdAt and updatedAt timestamp fields.

Session table schema differences from Auth.js

In Better Auth compared to Auth.js: uses 'token' instead of 'sessionToken'; uses 'expiresAt' instead of 'expires'; includes optional ipAddress and userAgent fields; includes createdAt and updatedAt timestamps.

Account table schema differences from Auth.js

In Better Auth compared to Auth.js: uses camelCase naming (e.g., refreshToken vs refresh_token); includes accountId field to distinguish from internal ID; uses providerId instead of provider; includes accessTokenExpiresAt and refreshTokenExpiresAt for token management; includes password field for credential authentication; removes type field (determined by providerId); removes token_type and session_state fields; includes createdAt and updatedAt timestamps.

Critical migration requirement for password-based accounts

When migrating from Auth.js to Better Auth, passwords must be stored in the 'account' table, not the user table. For each user with a password (including Phone Number plugin users), create a record in the account table with providerId set to 'credential'. Without this record, password-based sign-ins will fail.

Better Auth User table schema

The Better Auth 'user' table has the following fields: id (string, primary key), name (string, required), email (string, required, unique), emailVerified (boolean, required), image (string, optional), createdAt (Date), updatedAt (Date).

Better Auth Session table schema

The Better Auth 'session' table has the following fields: id (string, primary key), userId (string, foreign key to user.id with cascade delete), token (string, unique), expiresAt (Date), ipAddress (string, optional), userAgent (string, optional), createdAt (Date), updatedAt (Date).

Better Auth Account table schema

The Better Auth 'account' table has the following fields: id (string, primary key), userId (string, foreign key to user.id with cascade delete), accountId (string), providerId (string), accessToken (string, optional), refreshToken (string, optional), accessTokenExpiresAt (Date, optional), refreshTokenExpiresAt (Date, optional), scope (string, optional), idToken (string, optional), password (string, optional), createdAt (Date), updatedAt (Date).

VerificationToken table schema differences from Auth.js

In Better Auth compared to Auth.js: uses 'Verification' table instead of 'VerificationToken'; uses a single id primary key instead of composite key (identifier, token); uses 'value' instead of 'token' to support various verification types; uses 'expiresAt' instead of 'expires'; includes createdAt and updatedAt timestamps.

Recommended database indexes for Better Auth

Recommended database indexes: users table on email; accounts table on userId; sessions table on userId and token; verifications table on identifier; invitations table on email and organizationId (organization plugin); members table on userId and organizationId (organization plugin); organizations table on slug (organization plugin); passkey table on userId (passkey plugin); twoFactor table on secret (twoFactor plugin).

SQLite database configuration

To use SQLite with Better Auth, import betterAuth from 'better-auth' and Database from 'better-sqlite3', then pass `database: new Database('./sqlite.db')` to the betterAuth configuration object.

PostgreSQL database configuration

To use PostgreSQL with Better Auth, import betterAuth from 'better-auth' and Pool from 'pg', then pass `database: new Pool({ // connection options })` to the betterAuth configuration object.

MySQL database configuration

To use MySQL with Better Auth, import betterAuth from 'better-auth' and createPool from 'mysql2/promise', then pass `database: createPool({ // connection options })` to the betterAuth configuration object.

Drizzle ORM adapter configuration

To use Drizzle ORM adapter with Better Auth, import betterAuth from 'better-auth' and drizzleAdapter from 'better-auth/adapters/drizzle'. Pass `database: drizzleAdapter(db, { provider: 'pg' })` to the configuration, where provider can be 'pg', 'mysql', or 'sqlite'.

MongoDB adapter configuration

To use MongoDB adapter with Better Auth, import betterAuth from 'better-auth' and mongodbAdapter from 'better-auth/adapters/mongodb'. Pass `database: mongodbAdapter(client)` to the configuration, where client is your MongoDB client instance.

Prisma ORM adapter configuration

To use Prisma ORM adapter with Better Auth, import betterAuth from 'better-auth' and prismaAdapter from 'better-auth/adapters/prisma'. Create a PrismaClient instance and pass `database: prismaAdapter(prisma, { provider: 'sqlite' })` to the configuration, where provider can be 'sqlite', 'mysql', 'postgresql', etc.

Prisma client installation for Nitro

Install Prisma client as a dependency with @prisma/client. Install prisma itself as a dev dependency with -D prisma flag.

Initialize Prisma schema

Generate a schema.prisma file by running: npx prisma init. This creates the prisma directory and initial schema file.

Basic Prisma schema for Better Auth

The Prisma schema should specify the generator as prisma-client-js and configure the datasource with the appropriate database provider. For development, sqlite can be used with url set to env("DATABASE_URL"). Production environments should use PostgreSQL or other production-ready databases.

Generate Prisma client and sync database

Run npx prisma db push to generate the Prisma client and sync the database schema.

Give your agent this brain