diff --git a/docs/content/docs/concepts/database.mdx b/docs/content/docs/concepts/database.mdx
index 068718f647..e8a51173bc 100644
--- a/docs/content/docs/concepts/database.mdx
+++ b/docs/content/docs/concepts/database.mdx
@@ -337,6 +337,7 @@ Table Name: `user`
name: "email",
type: "string",
description: "User's email address for communication and login",
+ isUnique: true,
},
{
name: "emailVerified",
diff --git a/docs/content/docs/concepts/rate-limit.mdx b/docs/content/docs/concepts/rate-limit.mdx
index b7c950987f..663aacff98 100644
--- a/docs/content/docs/concepts/rate-limit.mdx
+++ b/docs/content/docs/concepts/rate-limit.mdx
@@ -291,18 +291,19 @@ Table Name: `rateLimit`
isPrimaryKey: true
},
{
- name: "key",
- type: "string",
+ name: "key",
+ type: "string",
description: "Unique identifier for each rate limit key",
+ isUnique: true,
},
{
- name: "count",
- type: "integer",
- description: "Time window in seconds"
+ name: "count",
+ type: "integer",
+ description: "Number of requests made in the current window"
},
- {
- name: "lastRequest",
- type: "bigint",
- description: "Max requests in the window"
+ {
+ name: "lastRequest",
+ type: "bigint",
+ description: "Timestamp of the last request (epoch ms)"
}]}
/>
diff --git a/docs/content/docs/guides/next-auth-migration-guide.mdx b/docs/content/docs/guides/next-auth-migration-guide.mdx
index b03ac610d0..2d0bfd4364 100644
--- a/docs/content/docs/guides/next-auth-migration-guide.mdx
+++ b/docs/content/docs/guides/next-auth-migration-guide.mdx
@@ -382,6 +382,7 @@ Just like Auth.js has database models, Better Auth also has a core schema. In th
name: "email",
type: "string",
description: "User's email address for communication and login",
+ isUnique: true,
},
{
name: "emailVerified",
diff --git a/docs/content/docs/plugins/2fa.mdx b/docs/content/docs/plugins/2fa.mdx
index dab2dfb073..5f66b4a7c2 100644
--- a/docs/content/docs/plugins/2fa.mdx
+++ b/docs/content/docs/plugins/2fa.mdx
@@ -482,8 +482,8 @@ Table: `twoFactor`
fields={[
{ name: "id", type: "string", description: "The ID of the two factor authentication.", isPrimaryKey: true },
{ name: "userId", type: "string", description: "The ID of the user", isForeignKey: true },
- { name: "secret", type: "string", description: "The secret used to generate the TOTP code.", isOptional: true },
- { name: "backupCodes", type: "string", description: "The backup codes used to recover access to the account if the user loses access to their phone or email.", isOptional: true },
+ { name: "secret", type: "string", description: "The secret used to generate the TOTP code." },
+ { name: "backupCodes", type: "string", description: "The backup codes used to recover access to the account if the user loses access to their phone or email." },
]}
/>
diff --git a/docs/content/docs/plugins/api-key/reference.mdx b/docs/content/docs/plugins/api-key/reference.mdx
index af25739fc7..bf22a9a8da 100644
--- a/docs/content/docs/plugins/api-key/reference.mdx
+++ b/docs/content/docs/plugins/api-key/reference.mdx
@@ -497,11 +497,13 @@ Table: `apikey`
name: "enabled",
type: "boolean",
description: "Whether the API key is enabled.",
+ isOptional: true,
},
{
name: "rateLimitEnabled",
type: "boolean",
description: "Whether the API key has rate limiting enabled.",
+ isOptional: true,
},
{
name: "rateLimitTimeWindow",
@@ -521,6 +523,7 @@ Table: `apikey`
type: "number",
description:
"The number of requests made within the rate limit time window.",
+ isOptional: true,
},
{
name: "remaining",
@@ -558,7 +561,7 @@ Table: `apikey`
},
{
name: "metadata",
- type: "Object",
+ type: "string",
isOptional: true,
description: "Any additional metadata you want to store with the key.",
},
diff --git a/docs/content/docs/plugins/device-authorization.mdx b/docs/content/docs/plugins/device-authorization.mdx
index f89d0a72be..b1643430a5 100644
--- a/docs/content/docs/plugins/device-authorization.mdx
+++ b/docs/content/docs/plugins/device-authorization.mdx
@@ -611,12 +611,11 @@ Table Name: `deviceCode`
type: "string",
description: "The user-friendly code for verification",
},
- {
- name: "userId",
- type: "string",
+ {
+ name: "userId",
+ type: "string",
description: "The ID of the user who approved/denied",
- isOptional: true,
- isForeignKey: true
+ isOptional: true
},
{
name: "clientId",
@@ -652,15 +651,5 @@ Table Name: `deviceCode`
description: "Minimum seconds between polls",
isOptional: true
},
- {
- name: "createdAt",
- type: "Date",
- description: "When the request was created",
- },
- {
- name: "updatedAt",
- type: "Date",
- description: "When the request was last updated",
- }
]}
/>
diff --git a/docs/content/docs/plugins/oauth-provider.mdx b/docs/content/docs/plugins/oauth-provider.mdx
index ca152c0e34..2b0e2b021b 100644
--- a/docs/content/docs/plugins/oauth-provider.mdx
+++ b/docs/content/docs/plugins/oauth-provider.mdx
@@ -1601,7 +1601,7 @@ Table Name: `oauthClient`
name: "clientId",
type: "string",
description: "Unique identifier for each OAuth client",
- isPrimaryKey: true,
+ isUnique: true,
},
{
name: "clientSecret",
@@ -1652,17 +1652,18 @@ Table Name: `oauthClient`
type: "string",
description: "ID of the reference of the client owner if not a user. (optional)",
isOptional: true,
- isForeignKey: true,
},
{
name: "createdAt",
type: "Date",
description: "Timestamp of when the OAuth client was created",
+ isOptional: true,
},
{
name: "updatedAt",
type: "Date",
description: "Timestamp of when the OAuth client was last updated",
+ isOptional: true,
},
{
name: "name",
@@ -1722,7 +1723,12 @@ Table Name: `oauthClient`
name: "redirectUris",
type: "string[]",
description: "Array of of redirect uris",
- isRequired: true,
+ },
+ {
+ name: "postLogoutRedirectUris",
+ type: "string[]",
+ description: "Array of post-logout redirect URIs",
+ isOptional: true,
},
{
name: "tokenEndpointAuthMethod",
@@ -1754,6 +1760,12 @@ Table Name: `oauthClient`
description: "Type of OAuth client. Supports: ['web', 'native', 'user-agent-based']",
isOptional: true,
},
+ {
+ name: "requirePKCE",
+ type: "boolean",
+ description: "Whether PKCE is required for this client",
+ isOptional: true,
+ },
{
name: "metadata",
type: "json",
@@ -1779,14 +1791,12 @@ Table Name: `oauthRefreshToken`
name: "token",
type: "string",
description: "Hashed/encrypted refresh token",
- isRequired: true,
},
{
name: "clientId",
type: "string",
description: "ID of the OAuth client",
isForeignKey: true,
- isRequired: true,
references: { model: "oauthClient", field: "clientId" },
},
{
@@ -1794,7 +1804,7 @@ Table Name: `oauthRefreshToken`
type: "string",
description: "ID of the session used at issuance of the token (and still active)",
isForeignKey: true,
- isRequired: false,
+ isOptional: true,
references: { model: "session", field: "id" },
},
{
@@ -1802,7 +1812,6 @@ Table Name: `oauthRefreshToken`
type: "string",
description: "ID of the user associated with the token",
isForeignKey: true,
- isRequired: true,
references: { model: "user", field: "id" },
},
{
@@ -1810,13 +1819,11 @@ Table Name: `oauthRefreshToken`
type: "string",
description: "ID of the consented reference",
isOptional: true,
- isForeignKey: true,
},
{
name: "scopes",
type: "string[]",
description: "Array of granted scopes",
- isRequired: true,
},
{
name: "revoked",
@@ -1859,14 +1866,13 @@ Table Name: `oauthAccessToken`
name: "token",
type: "string",
description: "Hashed/encrypted access token",
- isRequired: true,
+ isUnique: true,
},
{
name: "clientId",
type: "string",
description: "ID of the OAuth client",
isForeignKey: true,
- isRequired: true,
references: { model: "oauthClient", field: "clientId" }
},
{
@@ -1898,18 +1904,16 @@ Table Name: `oauthAccessToken`
type: "string",
description: "ID of the consented reference",
isOptional: true,
- isForeignKey: true,
},
{
name: "scopes",
type: "string[]",
description: "Array of granted scopes",
- isRequired: true,
},
{
name: "createdAt",
type: "Date",
- description: "Timestamp when the token was created"
+ description: "Timestamp when the token was created",
},
{
name: "expiresAt",
@@ -1950,23 +1954,21 @@ Table Name: `oauthConsent`
type: "string",
description: "ID of the consented reference",
isOptional: true,
- isForeignKey: true,
},
{
name: "scopes",
- type: "string",
- description: "Comma-separated list of scopes consented to",
- isRequired: true
+ type: "string[]",
+ description: "Array of scopes consented to",
},
{
name: "createdAt",
type: "Date",
- description: "Timestamp of when the consent was given"
+ description: "Timestamp of when the consent was given",
},
{
name: "updatedAt",
type: "Date",
- description: "Timestamp of when the consent was last updated"
+ description: "Timestamp of when the consent was last updated",
},
]}
/>
diff --git a/docs/content/docs/plugins/oidc-provider.mdx b/docs/content/docs/plugins/oidc-provider.mdx
index a0079b3622..019caae91a 100644
--- a/docs/content/docs/plugins/oidc-provider.mdx
+++ b/docs/content/docs/plugins/oidc-provider.mdx
@@ -453,11 +453,11 @@ Table Name: `oauthApplication`
description: "Database ID of the OAuth client",
isPrimaryKey: true
},
- {
- name: "clientId",
- type: "string",
+ {
+ name: "clientId",
+ type: "string",
description: "Unique identifier for each OAuth client",
- isPrimaryKey: true
+ isUnique: true
},
{
name: "clientSecret",
@@ -465,17 +465,21 @@ Table Name: `oauthApplication`
description: "Secret key for the OAuth client. Optional for public clients using PKCE.",
isOptional: true
},
- {
- name: "name",
- type: "string",
- description: "Name of the OAuth client",
- isRequired: true
+ {
+ name: "icon",
+ type: "string",
+ description: "Icon of the OAuth client",
+ isOptional: true
+ },
+ {
+ name: "name",
+ type: "string",
+ description: "Name of the OAuth client"
},
{
name: "redirectUrls",
type: "string",
- description: "Comma-separated list of redirect URLs",
- isRequired: true
+ description: "Comma-separated list of redirect URLs"
},
{
name: "metadata",
@@ -486,26 +490,26 @@ Table Name: `oauthApplication`
{
name: "type",
type: "string",
- description: "Type of OAuth client (e.g., web, mobile)",
- isRequired: true
+ description: "Type of OAuth client (e.g., web, mobile)"
},
- {
- name: "disabled",
- type: "boolean",
+ {
+ name: "disabled",
+ type: "boolean",
description: "Indicates if the client is disabled",
- isRequired: true
+ isOptional: true
},
{
- name: "userId",
- type: "string",
+ name: "userId",
+ type: "string",
description: "ID of the user who owns the client. (optional)",
isOptional: true,
+ isForeignKey: true,
references: { model: "user", field: "id" }
},
- {
- name: "createdAt",
- type: "Date",
- description: "Timestamp of when the OAuth client was created"
+ {
+ name: "createdAt",
+ type: "Date",
+ description: "Timestamp of when the OAuth client was created"
},
{
name: "updatedAt",
@@ -528,27 +532,26 @@ Table Name: `oauthAccessToken`
isPrimaryKey: true
},
{
- name: "accessToken",
- type: "string",
+ name: "accessToken",
+ type: "string",
description: "Access token issued to the client",
+ isUnique: true
},
{
- name: "refreshToken",
- type: "string",
+ name: "refreshToken",
+ type: "string",
description: "Refresh token issued to the client",
- isRequired: true
+ isUnique: true
},
{
name: "accessTokenExpiresAt",
type: "Date",
- description: "Expiration date of the access token",
- isRequired: true
+ description: "Expiration date of the access token"
},
{
name: "refreshTokenExpiresAt",
type: "Date",
- description: "Expiration date of the refresh token",
- isRequired: true
+ description: "Expiration date of the refresh token"
},
{
name: "clientId",
@@ -558,22 +561,22 @@ Table Name: `oauthAccessToken`
references: { model: "oauthApplication", field: "clientId" }
},
{
- name: "userId",
- type: "string",
+ name: "userId",
+ type: "string",
description: "ID of the user associated with the token",
+ isOptional: true,
isForeignKey: true,
references: { model: "user", field: "id" }
},
{
name: "scopes",
type: "string",
- description: "Comma-separated list of scopes granted",
- isRequired: true
+ description: "Comma-separated list of scopes granted"
},
- {
- name: "createdAt",
- type: "Date",
- description: "Timestamp of when the access token was created"
+ {
+ name: "createdAt",
+ type: "Date",
+ description: "Timestamp of when the access token was created"
},
{
name: "updatedAt",
@@ -612,19 +615,17 @@ Table Name: `oauthConsent`
{
name: "scopes",
type: "string",
- description: "Comma-separated list of scopes consented to",
- isRequired: true
+ description: "Comma-separated list of scopes consented to"
},
{
name: "consentGiven",
type: "boolean",
- description: "Indicates if consent was given",
- isRequired: true
+ description: "Indicates if consent was given"
},
- {
- name: "createdAt",
- type: "Date",
- description: "Timestamp of when the consent was given"
+ {
+ name: "createdAt",
+ type: "Date",
+ description: "Timestamp of when the consent was given"
},
{
name: "updatedAt",
diff --git a/docs/content/docs/plugins/organization.mdx b/docs/content/docs/plugins/organization.mdx
index b287d40e25..d7aef44f62 100644
--- a/docs/content/docs/plugins/organization.mdx
+++ b/docs/content/docs/plugins/organization.mdx
@@ -2138,6 +2138,7 @@ Table Name: `teamMember`
name: "createdAt",
type: "Date",
description: "Timestamp of when the team member was created",
+ isOptional: true,
},
]}
/>
@@ -2167,6 +2168,7 @@ Table Name: `organization`
name: "slug",
type: "string",
description: "The slug of the organization",
+ isUnique: true,
},
{
name: "logo",
@@ -2258,6 +2260,7 @@ Table Name: `invitation`
name: "role",
type: "string",
description: "The role of the user in the organization",
+ isOptional: true,
},
{
name: "status",
@@ -2349,6 +2352,7 @@ Table Name: `organizationRole`
name: "updatedAt",
type: "Date",
description: "Timestamp of when the organization role was updated",
+ isOptional: true,
},
]}
/>
@@ -2416,6 +2420,7 @@ Table Name: `teamMember`
name: "createdAt",
type: "Date",
description: "Timestamp of when the team member was created",
+ isOptional: true,
},
]}
/>
diff --git a/docs/content/docs/plugins/scim.mdx b/docs/content/docs/plugins/scim.mdx
index cbcb51a635..d19ae9f7e4 100644
--- a/docs/content/docs/plugins/scim.mdx
+++ b/docs/content/docs/plugins/scim.mdx
@@ -455,11 +455,11 @@ The plugin requires additional fields in the `scimProvider` table to store the p
@@ -469,7 +469,7 @@ The `scimProvider` schema is extended as follows:
diff --git a/docs/content/docs/plugins/sso.mdx b/docs/content/docs/plugins/sso.mdx
index dfa325e9fb..b044672421 100644
--- a/docs/content/docs/plugins/sso.mdx
+++ b/docs/content/docs/plugins/sso.mdx
@@ -1406,15 +1406,15 @@ The plugin requires additional fields in the `ssoProvider` table to store the pr
@@ -1424,7 +1424,7 @@ The `ssoProvider` schema is extended as follows:
diff --git a/docs/content/docs/plugins/stripe.mdx b/docs/content/docs/plugins/stripe.mdx
index e474b589ab..5f4e70aea3 100644
--- a/docs/content/docs/plugins/stripe.mdx
+++ b/docs/content/docs/plugins/stripe.mdx
@@ -739,9 +739,9 @@ Table Name: `subscription`
description: "The Stripe subscription ID",
isOptional: true
},
- {
- name: "status",
- type: "string",
+ {
+ name: "status",
+ type: "string",
description: "The status of the subscription (active, canceled, etc.)",
defaultValue: "incomplete"
},
diff --git a/docs/content/docs/plugins/username.mdx b/docs/content/docs/plugins/username.mdx
index ae2c274ccc..507ce82394 100644
--- a/docs/content/docs/plugins/username.mdx
+++ b/docs/content/docs/plugins/username.mdx
@@ -345,13 +345,14 @@ The plugin requires 2 fields to be added to the user table:
name: "username",
type: "string",
description: "The username of the user",
- isUnique: true
+ isUnique: true,
+ isOptional: true
},
{
name: "displayUsername",
type: "string",
description: "Non normalized username of the user",
- isUnique: true
+ isOptional: true
},
]}
/>
diff --git a/landing/components/docs/mdx-components.tsx b/landing/components/docs/mdx-components.tsx
index 71596a8d03..069dce7344 100644
--- a/landing/components/docs/mdx-components.tsx
+++ b/landing/components/docs/mdx-components.tsx
@@ -95,10 +95,26 @@ interface Field {
isPrimaryKey?: boolean;
isForeignKey?: boolean;
isOptional?: boolean;
+ isUnique?: boolean;
}
+const typeAliases: Record = {
+ text: "string",
+ integer: "number",
+ int: "number",
+ bigint: "number",
+ float: "number",
+ double: "number",
+ decimal: "number",
+ bool: "boolean",
+ object: "json",
+ timestamp: "date",
+ datetime: "date",
+};
+
function TypeIcon({ type }: { type: string }) {
- const t = type.toLowerCase().replace("[]", "");
+ const raw = type.toLowerCase().replace("[]", "");
+ const t = typeAliases[raw] ?? raw;
const className = "size-3 shrink-0";
if (t === "string" || t === "text") {
@@ -202,7 +218,17 @@ type DrizzleProvider = "pg" | "mysql" | "sqlite";
function fieldToDBField(field: Field): DBFieldAttribute {
const t = field.type.toLowerCase();
- const type = (t === "text" ? "string" : t) as DBFieldAttribute["type"];
+ const isArray = t.endsWith("[]");
+ const raw = isArray ? t.slice(0, -2) : t;
+ const aliased = typeAliases[raw] ?? raw;
+ const type = (
+ isArray && (aliased === "string" || aliased === "number")
+ ? `${aliased}[]`
+ : isArray
+ ? t
+ : aliased
+ ) as DBFieldAttribute["type"];
+ const bigint = raw === "bigint";
let references: DBFieldAttribute["references"] | undefined;
if (field.isForeignKey && field.name.endsWith("Id")) {
@@ -218,7 +244,8 @@ function fieldToDBField(field: Field): DBFieldAttribute {
type,
required: field.isPrimaryKey ? true : !field.isOptional,
references,
- unique: false,
+ unique: field.isUnique ?? false,
+ bigint,
};
}