AUTH STARTER · ADDING A NEW PLUGIN
Adding a new plugin
Better Auth has more plugins than we ship — organization, custom rate-limits, JWT. Here's the pattern to add any of them.
Every plugin we shipped follows the same 5-step pattern. New plugins from Better Auth's plugin gallery (or your own) drop in the same way.
The pattern
- 1. Add a toggle to authConfig.plugins in auth.config.ts.
- 2. Add the server plugin to the plugins array in src/lib/auth.ts (before nextCookies()).
- 3. Add the client plugin to the plugins array in src/lib/auth-client.ts.
- 4. If the plugin adds DB fields or tables, update src/db/schema/auth.ts and run db:push.
- 5. If the plugin needs UI, create a component in src/components/auth/ and render it conditionally based on the config toggle.
Example — adding the organization plugin
// 1. auth.config.ts
plugins: {
organization: { enabled: true },
},
// 2. src/lib/auth.ts
import { organization } from "better-auth/plugins";
const plugins = [
// ...
...(authConfig.plugins.organization.enabled ? [organization()] : []),
nextCookies(), // ← must remain last
];
// 3. src/lib/auth-client.ts
import { organizationClient } from "better-auth/client/plugins";
const plugins = [
// ...
...(authConfig.plugins.organization.enabled ? [organizationClient()] : []),
];
// 4. Update db/schema/auth.ts with organization + member + invitation tables
// 5. Run bun run db:pushnextCookies() MUST stay last
Better Auth requires nextCookies() as the final plugin in the array. Add new plugins ABOVE it. Putting it anywhere else breaks cookie handling and you'll get hours of "why is session null" debugging.
Always toggle conditionally
Wrap every plugin in ...(authConfig.plugins.x.enabled ? [plugin()] : []). That way flipping the toggle off in config truly disables the plugin everywhere — server, client, and UI conditionals all read the same source.