Skip to main content

better-auth vs Lucia vs NextAuth: The Auth Library Landscape in 2026

·PkgPulse Team

TL;DR

Authentication in JavaScript has been in flux. NextAuth (now Auth.js) still dominates downloads, but better-auth is the fastest-growing newcomer with a genuinely better TypeScript DX, and Lucia filled a gap before sunsetting its abstraction layer. If you're starting a new TypeScript project today, better-auth is the most compelling choice — it's the first auth library that actually feels designed for TypeScript from the ground up.

Key Takeaways

  • better-auth: 50K → 500K weekly downloads in 12 months — the fastest-growing auth library
  • NextAuth v5 / Auth.js: ~1.5M weekly downloads — still dominant but rebranded and restructured
  • Lucia v3: Pivoted from full auth library to auth architecture guide — no longer recommended as a dependency
  • better-auth wins on TypeScript ergonomics, plugin system, and two-factor support
  • NextAuth wins on ecosystem size, documentation depth, and framework coverage
  • If you're using Next.js and want minimal setup: NextAuth. For maximum control and type safety: better-auth.

PackageWeekly Downloads6-Month GrowthFirst Release
next-auth~1.5M+8%2020
@auth/core~400K+45%2023
better-auth~500K+820%2024
lucia~150K-40%2022

Live data on PkgPulse →


The Full Story

NextAuth v5 / Auth.js: The Incumbent

NextAuth is the default choice for Next.js authentication. With ~1.5M weekly downloads and 7 years of ecosystem maturity, it's battle-tested across thousands of production applications.

The v5 rewrite (released as @auth/core) brought significant changes:

  • Framework-agnostic core (@auth/core) with adapters for Next.js, SvelteKit, Express, Astro, and Qwik
  • Edge runtime support
  • New universal auth() helper that works in both server and client contexts
  • Callbacks API remains but with cleaner TypeScript types

What's still frustrating about NextAuth:

// Config file can get unwieldy with all options
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
import { DrizzleAdapter } from "@auth/drizzle-adapter"

export const { handlers, signIn, signOut, auth } = NextAuth({
  adapter: DrizzleAdapter(db),
  providers: [GitHub],
  callbacks: {
    session({ session, token }) {
      // TypeScript doesn't automatically know what's in token
      // You must augment types manually
      session.user.id = token.sub as string
      return session
    }
  }
})

Type augmentation is required for any custom session properties — a friction point that better-auth eliminates.


better-auth: The TypeScript-First Challenger

better-auth takes the position that existing auth libraries weren't designed with TypeScript in mind, and it shows. Every part of the API is fully typed from configuration to session reading.

import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { twoFactor, magicLink, passkey } from "better-auth/plugins"

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "postgresql"
  }),
  plugins: [
    twoFactor(),       // TOTP + backup codes
    magicLink(),       // Email magic links
    passkey()          // WebAuthn/passkeys
  ],
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true
  }
})

// Client-side — fully typed, no config needed
import { createAuthClient } from "better-auth/react"
const { signIn, signUp, useSession } = createAuthClient()

// Session type is automatically inferred — no manual augmentation
const { data: session } = useSession()
console.log(session.user.id) // ✅ Fully typed

Why developers are switching:

  1. Plugin system: Two-factor auth, magic links, passkeys, OAuth, organization management — all as typed plugins
  2. No manual type augmentation: Session types are automatically inferred from your config
  3. Organization/multi-tenant support: Built-in team/organization features that NextAuth requires custom code for
  4. Edge-native: Designed for Cloudflare Workers, Vercel Edge, and Bun from day one
  5. Active development: ~3 releases per week in 2025-2026

Lucia: The Architecture Guide

Lucia was originally a lightweight auth library that gave developers full control without magic. In late 2024, its maintainer Pilcrow made a pivotal decision: rather than maintain a shrinking library as better-auth gained traction, he sunset Lucia as a dependency and turned it into an auth architecture guide.

This was a selfless move — he acknowledged that better-auth had surpassed Lucia and redirected developers accordingly.

Key quote from the Lucia readme:

"Lucia is no longer maintained. If you were using it, consider using better-auth instead."

For new projects, don't install Lucia. Read its documentation to understand auth patterns, then implement with better-auth or NextAuth.


Feature Comparison

Featurebetter-authNextAuth v5Lucia (archived)
TypeScript DX⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Session managementDB + JWTJWT-firstDB sessions
OAuth providers40+80+Manual
Two-factor authPlugin (built-in)CommunityManual
Magic linksPlugin (built-in)CommunityManual
Passkeys/WebAuthnPlugin (built-in)NoManual
Organization/teamsPlugin (built-in)NoNo
Email+passwordBuilt-inBuilt-inManual
Database adaptersDrizzle, Prisma, Mongoose, Kysely15+Custom
Framework supportAny (Node, Edge, Bun)Next.js-first + othersAny
Bundle size~45KB~25KB core~12KB
Weekly downloads~500K~1.5M~150K

Session Strategies

NextAuth v5: JWT by default

// JWT session (default — no database needed):
export const { handlers, auth } = NextAuth({
  providers: [GitHub],
  // No adapter = JWT sessions
})

// Database sessions (with adapter):
export const { handlers, auth } = NextAuth({
  adapter: DrizzleAdapter(db),
  session: { strategy: "database" },
  providers: [GitHub],
})

better-auth: Database sessions by default

// better-auth always uses database sessions
// (no JWT session tokens floating around)
export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "postgresql" }),
  providers: [oauth({ ... })]
})

The choice between JWT and database sessions is a real architectural decision:

  • JWT: Stateless, works without a database, but can't be revoked without a blocklist
  • Database sessions: Instantly revocable, slightly more latency, requires DB query per request

Migration: NextAuth → better-auth

// NextAuth config (before):
export const { handlers, signIn, signOut, auth } = NextAuth({
  adapter: DrizzleAdapter(db),
  providers: [
    GitHub({ clientId: env.GITHUB_ID, clientSecret: env.GITHUB_SECRET }),
    Credentials({
      credentials: { email: {}, password: {} },
      authorize: async (credentials) => {
        // ... validate
      }
    })
  ],
  callbacks: {
    session: ({ session, token }) => {
      session.user.role = token.role
      return session
    }
  }
})

// better-auth config (after):
export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "postgresql" }),
  socialProviders: {
    github: {
      clientId: env.GITHUB_ID,
      clientSecret: env.GITHUB_SECRET
    }
  },
  emailAndPassword: { enabled: true },
  plugins: [
    admin()  // Role-based access built-in
  ]
})

When to Use Each

Choose NextAuth v5 / Auth.js if:

  • You're already using it in production — migration costs are real
  • You need the widest possible OAuth provider coverage (80+ providers)
  • Your team is more familiar with the NextAuth mental model
  • You need framework adapters for SvelteKit, Astro, or Qwik specifically
  • You want the most community resources and Stack Overflow answers

Choose better-auth if:

  • Starting a new TypeScript project in 2026
  • You want two-factor auth, passkeys, or magic links without community plugins
  • You need organization/multi-tenant support
  • Your TypeScript types shouldn't require manual augmentation
  • You're building on Cloudflare Workers, Bun, or an edge runtime

Don't use Lucia (as a library) if:

  • Starting a new project — read the docs, then use better-auth
  • You want maintained dependencies

Methodology

Data sourced from npm registry, GitHub star history, and community surveys. Download counts represent weekly average (Feb 2026). Bundle sizes measured with bundlephobia for the core package only.

Compare next-auth vs better-auth in real-time on PkgPulse →

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.