Better Enrollment

Database

The tables the plugin creates, every column, and how they are indexed.

Better Enrollment adds two tables, invite and inviteUse, and extends the organization plugin's organization table when org features are enabled. Run npx @better-auth/cli generate after installing to add them to your schema.

invite

One row per invitation. Status is only ever pending, accepted, or cancelled; expired is derived from expiresAt at read time, so there is no cron and nothing to sweep.

Tableinvite
Field
Type
Key
Description
id
string
PK
Unique identifier for each invite
type
string
-
Delivery type: "private" (email-bound, single use) or "public" (shareable link)
kind
string
-
What redeeming grants: "app", "org-join", or "org-create". Defaults to "app"
email ?
string
-
Address a private invite is bound to; null for public invites. Indexed
name ?
string
-
Optional display name for the invitee
role
string
-
Role merged into the user on redemption
tokenHash
string
UQ
Hash of the invite token; the raw token is never stored
status
string
-
"pending", "accepted", or "cancelled". "expired" is derived from expiresAt and never stored. Indexed
mode
string
-
Mode the invite was created for: "invite-only" or "open"
organizationId ?
string
-
Organization an org-join invite adds the invitee to. Plain column, no FK: accepted invites survive org deletion as audit records. Indexed
organizationRole ?
string
-
Role granted inside the organization on join
teamId ?
string
-
Team the invitee is added to, when the org plugin uses teams
presetSeatLimit ?
number
-
Seat limit applied to the organization founded through an org-create invite
preCreatedUserId ?
string
-
Shell user pre-created for a private invite; claimed by the invitee on accept
createdByUserId ?
string
-
User who created the invite. Plain column, no FK: the record outlives the inviter. Indexed
inviterName
string
-
Denormalized inviter name, kept for display and audit
inviterEmail
string
-
Denormalized inviter email, kept for display and audit
expiresAt ?
date
-
Expiry timestamp; null means the invite never expires. Indexed
maxUses ?
number
-
Redemption cap for public invites; null means unlimited
useCount
number
-
Successful redemptions so far. Defaults to 0
revokedAt ?
date
-
When the invite was revoked
revokedByUserId ?
string
-
User who revoked the invite
createdAt
date
-
When the invite was created
updatedAt
date
-
When the invite was last updated

inviteUse

Append-only audit table: one row per redemption. Rows are never updated, and they cascade only when their invite is deleted.

TableinviteUse
Field
Type
Key
Description
id
string
PK
Unique identifier for each redemption
inviteId
string
FK
The invite that was redeemed. Indexed References invite.id.
usedByUserId
string
-
User who redeemed the invite
inviteeEmail
string
-
Email of the invitee at redemption time
usedAt
date
-
When the invite was redeemed

organization (extension)

Columns added to the organization plugin's table, and only when org features are configured, so apps without the org plugin never get stray columns.

Tableorganization
Field
Type
Key
Description
seatLimit ?
number
-
Maximum member count for the organization; enforced on joins
disabledAt ?
date
-
When the organization was disabled by a platform control

Indexes

The schema indexes email, organizationId, tokenHash (unique), status, expiresAt, and createdByUserId. If your invite table grows into the millions, consider adding composite indexes (email, status) and (organizationId, status) in your own migrations; Better Auth's schema DSL only expresses single-column indexes.

Prisma example

A complete Prisma schema example lives in examples/prisma.

Last updated on

On this page