🟢The Backend
Lesson 77 of 117
30 min
Better Auth
The newer, you-own-the-schema TypeScript-first auth library.
Better Auth is the auth library rising fast in the TypeScript world. It arrived in late 2024, took off through 2025, and by 2026 it sits next to Auth.js as a serious default choice. It is TypeScript-first, you own the DB schema, and the plugin model is unusually clean.
Why people are switching
- You own the schema. Better Auth generates the SQL tables you need; they live in your migrations like any other table. Inspect, modify, query.
- Framework-agnostic. Works with Next, Remix, Hono, SvelteKit, Astro, Express, Solid Start. The core is just functions.
- Plugins are first-class. Passkeys, organizations, 2FA, magic links, OAuth proxy: each is a plugin you opt in to.
- End-to-end types.The client knows what the server configured. No casting, no "user as any".
Install
bash
pnpm add better-auth
pnpm add -D @better-auth/cliThe auth instance
lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg" }),
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
},
},
});Generate the schema
bash
npx @better-auth/cli generate
# Adds user, session, account, verification tables to your Drizzle schema
# Then run your usual migration step
pnpm drizzle-kit pushThe schema is yours
After generation, those tables are normal tables. Add columns (
plan, company, etc.) directly. Just rerun generate after Better Auth upgrades to merge in any new required columns.The route handler
app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { POST, GET } = toNextJsHandler(auth);Client SDK (typed)
lib/auth-client.ts
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_APP_URL,
});
export const { signIn, signOut, signUp, useSession } = authClient;tsx
"use client";
import { useSession, signIn, signOut } from "@/lib/auth-client";
export function Nav() {
const { data: session, isPending } = useSession();
if (isPending) return null;
return session ? (
<button onClick={() => signOut()}>Sign out, {session.user.name}</button>
) : (
<button onClick={() => signIn.social({ provider: "github" })}>
Sign in with GitHub
</button>
);
}Reading the session on the server
tsx
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
export default async function Dashboard() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session) redirect("/login");
return <h1>Hello, {session.user.name}</h1>;
}Plugins that ship
- passkey: WebAuthn / FIDO2 with one config line.
- organization: multi-tenant orgs, invites, roles.
- twoFactor: TOTP, with backup codes.
- magicLink: email-based passwordless.
- admin: built-in admin user model with banning.
- jwt: emit JWT alongside session cookies, for mobile or third-party consumers.
Better Auth vs Auth.js: how to pick
- Better Auth wins for: organizations/multi-tenant, passkeys out of the box, owning the schema, fewer surprises in non-Next frameworks.
- Auth.js wins for: enormous provider ecosystem, deep Next App Router integration, more battle-tested in production today.
- New TypeScript project, Drizzle or Prisma, Next 16: either works. Better Auth's DX edge is the recommendation in 2026 unless you need an obscure provider Auth.js already supports.
Auth.js itself announced a collaboration with Better Auth in 2025, so the ecosystems are friendlier than they look.
Quiz
Quiz1 / 3
What is the biggest practical difference between Better Auth and Auth.js?
Recap
- Better Auth = TS-first, you-own-the-schema, framework-agnostic.
- Plugins for passkeys, orgs, 2FA, magic links, admin, JWT.
- Typed client SDK with
useSession,signIn,signOut. - Pick Better Auth if you want multi-tenancy or passkeys, Auth.js if you need an obscure provider or are deep in legacy Auth.js setup.