Before You Begin
Before starting the migration process, set up Better Auth in your project. Follow the Better Auth installation guide to get started.
Mapping Existing Columns
Instead of altering your existing database column names, you can map them to match Better Auth’s expected structure. This allows you to retain your current database schema.
User Schema
Map the following fields in the user schema:
- (next-auth v4)
emailVerified: datetime → boolean
Session Schema
Map the following fields in the session schema:
expires→expiresAtsessionToken→token- (next-auth v4) add
createdAtwith datetime type - (next-auth v4) add
updatedAtwith datetime type
Make sure to have createdAt and updatedAt fields on your session schema.
Account Schema
Map these fields in the account schema:
- (next-auth v4)
provider→providerId providerAccountId→accountIdrefresh_token→refreshTokenaccess_token→accessToken- (next-auth v3)
access_token_expires→accessTokenExpiresAtand int → datetime - (next-auth v4)
expires_at→accessTokenExpiresAtand int → datetime id_token→idToken- (next-auth v4) add
createdAtwith datetime type - (next-auth v4) add
updatedAtwith datetime type
Remove the session_state, type, and token_type fields, as they are not required by Better Auth.
export const auth = betterAuth({
// Other configs
account: {
fields: {
accountId: "providerAccountId",
refreshToken: "refresh_token",
accessToken: "access_token",
accessTokenExpiresAt: "access_token_expires",
idToken: "id_token",
},
},
})Note: If you use ORM adapters, you can map these fields in your schema file.
Example with Prisma:
model Session {
id String @id @default(cuid())
expiresAt DateTime @map("expires") // Map your existing `expires` field to Better Auth's `expiresAt`
token String @map("sessionToken") // Map your existing `sessionToken` field to Better Auth's `token`
userId String
user User @relation(fields: [userId], references: [id])
}Make sure to have createdAt and updatedAt fields on your account schema.
Update the Route Handler
In the app/api/auth folder, rename the [...nextauth] file to [...all] to avoid confusion. Then, update the route.ts file as follows:
import { toNextJsHandler } from "better-auth/next-js"
import { auth } from "~/server/auth"
export const { POST, GET } = toNextJsHandler(auth)Update the Client
Create a file named auth-client.ts in the lib folder. Add the following code:
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
baseURL: process.env.BASE_URL!, // Optional if the API base URL matches the frontend
})
export const { signIn, signOut, useSession } = authClientSocial Login
Update your social login actions to use Better Auth. For example, for Discord:
import { signIn } from "~/lib/auth-client"
export const signInDiscord = async () => {
const data = await signIn.social({
provider: "discord",
})
return data
}Update useSession Calls
Replace useSession calls with Better Auth’s version. Example:
import { useSession } from "~/lib/auth-client";
export const Profile = () => {
const { data } = useSession();
return (
<div>
<pre>
{JSON.stringify(data, null, 2)}
</pre>
</div>
);
};Server-Side Session Handling
Use the auth instance to get session data on the server:
"use server"
import { auth } from "~/server/auth"
import { headers } from "next/headers"
export const protectedAction = async () => {
const session = await auth.api.getSession({
headers: await headers(),
})
}Middleware
To protect routes with middleware, refer to the Next.js middleware guide.
Wrapping Up
Congratulations! You’ve successfully migrated from NextAuth.js to Better Auth. For a complete implementation with multiple authentication methods, check out the demo repository.
Better Auth offers greater flexibility and more features—be sure to explore the documentation to unlock its full potential.