docs: clarify generateId behavior and mixed ID types (#5173)

Co-authored-by: Maxwell <145994855+ping-maxwell@users.noreply.github.com>
This commit is contained in:
Ahmed Abdellahi Abdat
2025-10-15 12:45:26 +00:00
committed by GitHub
co-authored by Maxwell
parent 58ffd0bc92
commit 5ebdef19c1
+85 -5
View File
@@ -471,11 +471,11 @@ export const auth = betterAuth({
### ID Generation
Better Auth by default will generate unique IDs for users, sessions, and other entities. If you want to customize how IDs are generated, you can configure this in the `advanced.database.generateId` option in your auth config.
Better Auth by default will generate unique IDs for users, sessions, and other entities. You can customize ID generation behavior using the `advanced.database.generateId` option or `advanced.database.useNumberId`.
You can also disable ID generation by setting the `advanced.database.generateId` option to `false`. This will assume your database will generate the ID automatically.
#### Option 1: Let Database Generate IDs
**Example: Automatic Database IDs**
Setting `generateId` to `false` disables ID generation globally, letting your database handle all ID generation:
```ts title="auth.ts"
import { betterAuth } from "better-auth";
@@ -485,13 +485,48 @@ export const auth = betterAuth({
database: db,
advanced: {
database: {
generateId: false,
generateId: false, // Database generates all IDs
},
},
});
```
**Example: Using a Custom ID Generator**
<Callout type="info">
**Note**: For auto-incrementing numeric IDs (serial, auto_increment), use `useNumberId: true` instead (see the Numeric IDs section below).
</Callout>
#### Option 2: Custom ID Generation Function
Use a function to generate IDs. You can return `false` or `undefined` from the function to let the database generate the ID for specific models:
```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { db } from "./db";
export const auth = betterAuth({
database: db,
advanced: {
database: {
generateId: (options) => {
// Let database auto-generate for specific models
if (options.model === "user" || options.model === "users") {
return false; // Let database generate ID
}
// Generate UUIDs for other tables
return crypto.randomUUID();
},
},
},
});
```
<Callout type="info">
**Important**: Returning `false` or `undefined` from the `generateId` function lets the database handle ID generation for that specific model. Setting `generateId: false` (without a function) disables ID generation for **all** tables.
</Callout>
#### Option 3: Consistent Custom ID Generator
Generate the same type of ID for all tables:
```ts title="auth.ts"
import { betterAuth } from "better-auth";
@@ -538,6 +573,50 @@ export const auth = betterAuth({
this is normal. It's also expected that all id values passed to Better-Auth (eg via an endpoint body) is expected to be a string.
</Callout>
### Mixed ID Types
If you need different ID types across tables (e.g., integer IDs for users, UUID strings for sessions/accounts/verification), use a `generateId` function instead of `useNumberId`.
<Callout type="warn">
**Do NOT use `useNumberId` when mixing ID types**. The `useNumberId` option is global and affects all tables. It will disable internal ID generation and expect all IDs to be numbers.
</Callout>
**Example: Integer IDs for Users, UUIDs for Other Tables**
```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { db } from "./db";
export const auth = betterAuth({
database: db,
user: {
modelName: "users", // PostgreSQL: id serial primary key
},
session: {
modelName: "session", // PostgreSQL: id text primary key
},
advanced: {
database: {
// Do NOT set useNumberId - it's global and affects all tables
generateId: (options) => {
if (options.model === "user" || options.model === "users") {
return false; // Let PostgreSQL serial generate it
}
return crypto.randomUUID(); // UUIDs for session, account, verification
},
},
},
});
```
This configuration allows you to:
- Use database auto-increment (serial, auto_increment, etc.) for the users table
- Generate UUIDs for all other tables (session, account, verification)
- Maintain compatibility with existing schemas that use different ID types
<Callout type="info">
**Use Case**: This is particularly useful when migrating from other authentication providers (like Clerk) where you have existing users with integer IDs but want UUID strings for new tables.
</Callout>
### Database Hooks
@@ -616,6 +695,7 @@ export const auth = betterAuth({
});
```
#### Throwing Errors
If you want to stop the database hook from proceeding, you can throw errors using the `APIError` class imported from `better-auth/api`.