Skip to main content
This guide walks through migrating a project from Auth.js (formerly NextAuth.js) to Better Auth. The two libraries have different design philosophies, so the migration requires some planning.
If your Auth.js setup is working well there is no urgent need to migrate. Better Auth continues to add features previously exclusive to Auth.js, and we welcome the opportunity to earn your adoption on new or greenfield projects.
1

Create the Better Auth instance

Follow the installation guide to add Better Auth to your project. Here is a side-by-side comparison of a minimal GitHub OAuth config:
auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [GitHub],
});
2

Create the client instance

Better Auth ships a separate client package for browser/React usage:
auth-client.ts
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient();
3

Update the route handler

Rename /app/api/auth/[...nextauth] to /app/api/auth/[...all], then update route.ts:
app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/lib/auth";

export const { GET, POST } = handlers;
4

Migrate client-side session management

Sign in

"use client";
import { signIn } from "next-auth/react";

signIn("github");

Sign out

"use client";
import { signOut } from "next-auth/react";

signOut();

Get session (client)

"use client";
import { useSession } from "next-auth/react";

const { data, status, update } = useSession();
5

Migrate server-side session management

Get session (server)

import { auth } from "@/lib/auth";

const session = await auth();

Sign out (server)

import { signOut } from "@/lib/auth";

await signOut();
6

Protect routes

Better Auth recommends checking the session on each page or route rather than relying on middleware for full authorization.
app/dashboard/page.tsx
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";

export default async function DashboardPage() {
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) redirect("/sign-in");

  return <h1>Welcome {session.user.name}</h1>;
}
7

Migrate the database

If you were using the Auth.js database session strategy you will need to migrate your data. The table below summarises the schema differences.

User table

FieldAuth.jsBetter Auth
nameoptionalrequired
emailoptionalrequired, unique
emailVerifiedDate | nullboolean
createdAtDate
updatedAtDate

Session table

FieldAuth.jsBetter Auth
sessionTokenrenamed to token
expiresDaterenamed to expiresAt
ipAddressstring | null
userAgentstring | null
createdAtDate
updatedAtDate

Account table

FieldAuth.jsBetter Auth
providerrenamed to providerId
providerAccountIdrenamed to accountId
refresh_tokensnake_caserefreshToken (camelCase)
access_tokensnake_caseaccessToken (camelCase)
expires_atnumberaccessTokenExpiresAt: Date
typeremoved (derived from providerId)
passwordadded for credential accounts

VerificationToken → Verification

FieldAuth.jsBetter Auth
composite PK (identifier, token)replaced by id: string
tokenrenamed to value
expiresDaterenamed to expiresAt
createdAtDate
updatedAtDate

Wrapping up

For a full implementation example see the Next.js demo app. Need help? Join the community or email contact@better-auth.com.