Use this file to discover all available pages before exploring further.
This page covers breaking changes between major versions of @convex-dev/better-auth. Expand the section for the version you are upgrading to and follow the steps in order.
Always check the CHANGELOG for breaking changes in minor and patch versions as well.
The passkey plugin is no longer bundled with the component. If you are using passkey, switch to Local Install and install @better-auth/passkey directly. The passkey table has been removed from the component schema.
The redirectURLs field on the oauthApplication table has been renamed to redirectUrls. This only applies if you are using the OIDC provider plugin (a “Sign in with MyApp” setup). If you have existing data in this table, use the Convex migrations component to rename the field before deploying.
Check your dependencies for other Better Auth packages and pin them all to 1.4.9. For example, if you are using @better-auth/expo, it also needs to be upgraded.
The plugin now requires the auth config object. Also set jwksRotateOnTokenGenerationError: true initially so keys can be rotated when an algorithm mismatch occurs (RS256 replaced EdDSA). You can disable it later.
Replace the previous server utility functions with the new framework-specific helpers. The new functions only accept a function reference and arguments — no token configuration is needed.
Set expectAuth: true on ConvexQueryClient so that authenticated data from server render is not lost after first render. Also remove the unused Wrap provider if you have one.
src/router.tsx
const convexQueryClient = new ConvexQueryClient(convexUrl, { expectAuth: true,});
Replace getStaticAuth in convex/betterAuth/auth.ts with a simple createAuth call.
This file should only contain your auth export for schema generation. If it is imported at runtime it will trigger errors due to missing environment variables.
convex/betterAuth/auth.ts
import { createAuth } from "../auth";export const auth = createAuth({} as any);
The onUpdate hook now receives the new doc as the second parameter and the old doc as the third. Update any triggers accordingly — the old doc can be omitted from the signature if you don’t need it.
convex/auth.ts
export const authComponent = createClient<DataModel>(components.betterAuth, { authFunctions, triggers: { user: { // Before: onUpdate: async (ctx, oldDoc, newDoc) => { onUpdate: async (ctx, newDoc, oldDoc) => { // oldDoc can be left out of the signature if not needed }, }, },});
Storing your app user ID in the Better Auth user table is deprecated and will be removed in a future release. See the migrate-userid guide for the full migration steps.
Convert hooks from createAuthFunctions to triggers
The onCreateUser, onUpdateUser, and onDeleteUser hooks from betterAuthComponent.createAuthFunctions() have been replaced by triggers. See the Triggers guide for more information.
convex/auth.ts
export const authComponent = createClient<DataModel>( components.betterAuth, { authFunctions, triggers: { user: { onCreate: async (ctx, authUser) => { // Any onCreateUser logic goes here const userId = await ctx.db.insert('users', { email: authUser.email, }); // Required when migrating from previous versions to avoid a // database migration — sets the userId on the component user table. await authComponent.setUserId(ctx, authUser._id, userId); }, onUpdate: async (ctx, oldUser, newUser) => { // Any onUpdateUser logic goes here }, onDelete: async (ctx, authUser) => { await ctx.db.delete(authUser.userId as Id<'users'>); }, }, }, },);export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi();
Move createAuth to convex/auth.ts. The Convex database adapter is now provided through authComponent.adapter(ctx), and a GenericCtx type from the component library is used to type the ctx argument.
The subject property of the identity token is now the Better Auth user ID, not the app user ID. Replace direct subject usage with authComponent.getAuthUser(ctx).
authComponent.getAuthUser() now throws if the user is not found. Use authComponent.safeGetAuthUser() to restore the previous behavior of returning null.