Introduction
In this guide, we’ll walk through the steps to migrate a project from Auth.js to Better Auth. Since these projects have different design philosophies, the migration requires careful planning and work. If your current setup is working well, there’s no urgent need to migrate. Better Auth team continues to handle security patches and critical issues for Auth.js.
However, if you’re starting a new project or facing challenges with your current setup, we strongly recommend using Better Auth. Our roadmap includes features previously exclusive to Auth.js, and we hope this will unite the ecosystem more strongly without causing fragmentation.
1. Create Better Auth Instance
Before starting the migration process, set up Better Auth in your project. Follow the installation guide to get started.
For example, if you use the GitHub OAuth provider, here is a comparison of the auth.ts file.
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [GitHub],
})Now Better Auth supports stateless session management without any database. If you were using a Database adapter in Auth.js, you can refer to the Database models below to check the differences with Better Auth’s core schema.
2. Create Client Instance
This client instance includes a set of functions for interacting with the Better Auth server instance. For more information, see here.
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient()3. Update the Route Handler
Rename the /app/api/auth/[...nextauth] folder to /app/api/auth/[...all] to avoid confusion. Then, update the route.ts file as follows:
import { handlers } from "@/lib/auth"
export const { GET, POST } = handlers4. Session Management
In this section, we’ll look at how to manage sessions in Better Auth compared to Auth.js. For more information, see here.
Client-side
Sign In
Here are the differences between Auth.js and Better Auth for signing in users. For example, with the GitHub OAuth provider:
"use client"
import { signIn } from "next-auth/react"
signIn("github")
Sign Out
Here are the differences between Auth.js and Better Auth when signing out users.
"use client"
import { signOut } from "next-auth/react"
signOut()
Get Session
Here are the differences between Auth.js and Better Auth for getting the current active session.
"use client"
import { useSession } from "next-auth/react"
const { data, status, update } = useSession()
Server-side
Sign In
Here are the differences between Auth.js and Better Auth for signing in users. For example, with the GitHub OAuth provider:
import { signIn } from "@/lib/auth"
await signIn("github")
Sign Out
Here are the differences between Auth.js and Better Auth when signing out users.
import { signOut } from "@/lib/auth"
await signOut()
Get Session
Here are the differences between Auth.js and Better Auth for getting the current active session.
import { auth } from "@/lib/auth";
const session = await auth()
5. Protecting Resources
Proxy (Middleware) is not intended for slow data fetching. While Proxy can be helpful for optimistic checks such as permission-based redirects, it should not be used as a full session management or authorization solution. - Next.js docs
Auth.js offers approaches using Proxy (Middleware), but Better Auth recommend handling auth checks on each page or route rather than in a Proxy or Layout. Here is a basic example of protecting resources with Better Auth.
"use client";
import { authClient } from "@/lib/auth-client"
import { redirect } from "next/navigation"
const DashboardPage = () => {
const { data, error, isPending } = authClient.useSession();
if (isPending) {
return <div>Pending</div>;
}
if (!data || error) {
redirect("/sign-in");
}
return (
<div>
<h1>Welcome {data.user.name}</h1>
</div>
); };
export default DashboardPage;6. Database models
Both Auth.js and Better Auth provide stateless (JWT) and database session strategies. If you were using the database session strategy in Auth.js and plan to continue using it in Better Auth, you will also need to migrate your database.
Just like Auth.js has database models, Better Auth also has a core schema. In this section, we’ll compare the two and explore the differences between them.
Comparison
Table: User
name,email, andemailVerifiedare required in Better Auth, while optional in Auth.jsemailVerifieduses a boolean in Better Auth, while Auth.js uses a timestamp- Better Auth includes
createdAtandupdatedAttimestamps
Table: Session
- Better Auth uses
tokeninstead ofsessionToken - Better Auth uses
expiresAtinstead ofexpires - Better Auth includes
ipAddressanduserAgentfields - Better Auth includes
createdAtandupdatedAttimestamps
Table: Account
- Better Auth uses camelCase naming (e.g.
refreshTokenvsrefresh_token) - Better Auth includes
accountIdto distinguish between the account ID and internal ID - Better Auth uses
providerIdinstead ofprovider - Better Auth includes
accessTokenExpiresAtandrefreshTokenExpiresAtfor token management - Better Auth includes
passwordfield to support built-in credential authentication - Better Auth does not have a
typefield as it’s determined by theproviderId - Better Auth removes
token_typeandsession_statefields - Better Auth includes
createdAtandupdatedAttimestamps
Table: VerificationToken -> Verification
- Better Auth uses
Verificationtable instead ofVerificationToken - Better Auth uses a single
idprimary key instead of composite primary key - Better Auth uses
valueinstead oftokento support various verification types - Better Auth uses
expiresAtinstead ofexpires - Better Auth includes
createdAtandupdatedAttimestamps
If you were using Auth.js v4, note that v5 does not introduce any breaking
changes to the database schema. Optional fields like oauth_token_secret and
oauth_token can be removed if you are not using them. Rarely used fields
like refresh_token_expires_in can also be removed.
Customization
You may have extended the database models or implemented additional logic in Auth.js. Better Auth allows you to customize the core schema in a type-safe way. You can also define custom logic during the lifecycle of database operations. For more details, see Concepts - Database.
Wrapping Up
Now you’re ready to migrate from Auth.js to Better Auth. For a complete implementation with multiple authentication methods, check out the Next.js Demo App. Better Auth offers greater flexibility and more features, so be sure to explore the documentation to unlock its full potential.
If you need help with migration, join our community or reach out to contact@better-auth.com.