Better Auth
TypeScript-first, self-hosted authentication with full schema ownership
Overview
Better Auth is a TypeScript-first authentication library that gives you complete ownership of your auth schema and user data. Unlike Auth.js, it ships with a fully defined database schema (via Prisma or Drizzle adapters) and a rich plugin ecosystem covering 2FA, passkeys, organizations, API keys, and more.
It exposes a single catch-all route handler that wires up all auth endpoints automatically. The client-side SDK works across React, Vue, Svelte, and vanilla JS, making it framework-agnostic despite its TypeScript-first design.
In a monolith it runs as part of your app, sharing the same database. In a microservice setup, it can run as a standalone auth service with its own database, issuing tokens that other services validate.
Architecture fit
Key features
Trade-offs
Full data ownership — users never leave your database
You manage migrations, backups, and scaling
Richer schema than Auth.js — easier to extend
More setup than NextAuth for simple OAuth-only apps
Plugin system avoids maintaining fork for custom features
Smaller community than Auth.js or Passport
Works in monolith or standalone microservice
Microservice mode adds a network hop per session check
✓ When to use
- →Next.js / SvelteKit / Nuxt apps that need custom auth logic
- →Teams that want self-hosted auth without building from scratch
- →Apps requiring organizations, API keys, or passkeys out of the box
- →Projects already using Prisma or Drizzle
✗ When NOT to use
- →Enterprise SSO/SAML requirements — use WorkOS or Auth0
- →Teams who want zero auth infra to operate — use Clerk
- →Simple prototypes that only need one OAuth provider
Implementation
TypeScript// lib/auth.ts
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { twoFactor, organization } from "better-auth/plugins";
export const auth = betterAuth({
database: prismaAdapter(prisma, { provider: "postgresql" }),
emailAndPassword: { enabled: true },
socialProviders: {
github: { clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! },
google: { clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! },
},
plugins: [twoFactor(), organization()],
});
// app/api/auth/[...all]/route.ts
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth);
// middleware.ts — protect routes server-side
import { betterFetch } from "@better-fetch/fetch";
import type { Session } from "better-auth/types";
export async function middleware(req: NextRequest) {
const { data: session } = await betterFetch<Session>("/api/auth/get-session", {
baseURL: req.nextUrl.origin,
headers: { cookie: req.headers.get("cookie") ?? "" },
});
if (!session) return NextResponse.redirect(new URL("/login", req.url));
return NextResponse.next();
}
// Client usage (React)
import { authClient } from "@/lib/auth-client";
const { data: session } = await authClient.useSession();
await authClient.signIn.social({ provider: "github" });In production
Uses Better Auth to secure their database-as-a-service platform
Adopted widely in the Next.js + Drizzle/Prisma ecosystem since 2024
Other frameworks
Auth.js (NextAuth v5)
The most popular authentication library for Next.js and the JS ecosystem
Clerk
Managed authentication with prebuilt UI components — zero infrastructure
Lucia
Minimal session management primitives — you control the auth logic
Passport.js
The original Node.js authentication middleware — 500+ strategies