Open Source Auth for Next.js: Escape Vendor Lock-In for Good

By Aziz Ali
better-authnextjsauthopen-sourcevendor-lock-in

Clerk's free tier caps at 10,000 monthly active users. Sounds generous until you hit it — then you're looking at $25/month minimum, scaling upward as your app grows. I've watched founders pay $200/month in auth fees before they made their first $1,000 in revenue. That's not a tool; that's a tax on your success.

There's a better way. Open source auth for Next.js exists, it's production-ready, and it won't send you an invoice when your app takes off.

The Real Problem with Managed Auth

The cost is annoying, but it's not the real problem. The real problem is your users live in someone else's database.

When you use Clerk, your user records, sessions, and tokens are stored in Clerk's infrastructure. Try migrating 50,000 users off Clerk — exporting hashed passwords, re-linking OAuth accounts, rebuilding session logic. It's a multi-week engineering project, and Clerk knows it. That's the lock-in.

Building a SaaS with no vendor lock-in isn't just a philosophical preference. It's a survival skill for bootstrapped founders who don't want critical infrastructure owned by a third party with its own pricing roadmap.

Why Better-Auth is the Right Open Source Auth for Next.js

Better-Auth is a TypeScript-first, self-hosted auth library. It's not NextAuth (which is fine but limited in its feature set). It's not a managed service. It's code that lives in your repo, runs on your server, and stores data in your database.

Here's what you get out of the box:

  • Email/password authentication with secure hashing
  • OAuth social login (Google, GitHub, Discord, and more)
  • Magic links and OTP verification
  • Two-factor authentication (TOTP + backup codes)
  • Passkey (WebAuthn) support
  • Role-based access control
  • Multi-tenant organization support
  • Full Drizzle ORM and Prisma adapters

No per-user pricing. No rate limits on auth calls. No surprise bill when you hit the front page of Hacker News.

Setting Up Better-Auth in a Next.js App

Here's a real setup — not a toy example. This is roughly what I use in production.

Install:

bun add better-auth

Configure your 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", // or "mysql" or "sqlite"
  }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },
  plugins: [twoFactor()],
});

Mount the API route:

// app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { GET, POST } = toNextJsHandler(auth);

Create a client:

// lib/auth-client.ts
import { createAuthClient } from "better-auth/react";

export const { signIn, signOut, useSession } = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL!,
});

That's your complete auth setup. No dashboard to configure. No webhook to register. No third-party dependency in your production critical path.

Better-Auth vs Clerk vs NextAuth — Side by Side

Feature Better-Auth Clerk NextAuth v5
Pricing Free (self-hosted) $25+/mo at scale Free
User data location Your DB Clerk's servers Your DB
Full TypeScript ⚠️ Partial
2FA built-in ❌ Manual
Passkeys ⚠️ Experimental
Multi-tenant orgs ❌ Manual
Data portability ✅ Full control ❌ Locked in ✅ Full control
Drizzle ORM adapter ⚠️ Community only
Self-hosted

I wrote a detailed Better-Auth vs Clerk breakdown if you want the full picture. The short version: Clerk is polished but expensive and trapping. Better-Auth gives you everything Clerk does, minus the bill and the lock-in.

How the Auth Flow Actually Works

flowchart TD
    A[User visits /login] --> B{Has account?}
    B -->|No| C[Sign up with email or OAuth]
    B -->|Yes| D[Sign in]
    C --> E[Better-Auth creates user in YOUR DB]
    D --> F[Session token issued]
    E --> F
    F --> G[Token stored in HTTP-only cookie]
    G --> H[useSession reads auth state client-side]
    H --> I[Protected routes check session server-side]
    I --> J[User accesses app ✅]

Everything happens on your infrastructure. Better-Auth issues tokens, stores sessions, and validates requests — all within your deployment, using your database.

When I'd Still Consider Clerk

I'll be honest: Clerk's UI components are excellent. If you're building a very early prototype and want a login screen that looks polished in 15 minutes, Clerk ships that. But the moment you're building something real — something you plan to grow — you should own your auth stack.

The Better-Auth setup guide for React shows how to build those same polished UI components yourself with shadcn/ui in under an hour. You get full control AND a great UX.

FAQ

Is Better-Auth production-ready? Yes. Better-Auth is actively maintained, has TypeScript types throughout, and is used in production apps. It's not a toy library — it handles enterprise features like 2FA, passkeys, and multi-tenant organizations.

Can I migrate from Clerk to Better-Auth? Yes, but it requires effort. You'll need to export user data from Clerk, re-create accounts in your database, and handle password hash migration. The earlier you switch, the less painful it is.

Does Better-Auth work with Drizzle ORM? Yes — Better-Auth has a first-class Drizzle ORM adapter. It auto-generates the required schema tables and handles all DB queries. This is one reason I prefer it for TanStack Start + Drizzle setups.

What's the difference between Better-Auth and NextAuth? NextAuth is solid for basic OAuth flows but thin on advanced features like 2FA, passkeys, and multi-tenancy. Better-Auth was built from scratch to be a complete auth solution, not just an OAuth wrapper.

Does Better-Auth work with App Router (Next.js 13+)? Yes. Better-Auth ships a toNextJsHandler adapter that works natively with the App Router. You mount it at app/api/auth/[...all]/route.ts and you're done.


If you're tired of wiring auth, Stripe, email, and database adapters from scratch on every project — BetterStarter ships all of this pre-configured on TanStack Start + Bun. $99 one-time, no monthly bill, and you own every line of code.