Authentication in Next.js 14: NextAuth v5, Clerk, or Roll Your Own?
After shipping auth on 10+ Next.js projects, here's how I decide between NextAuth (Auth.js), Clerk, and custom JWT — with the gotchas each path hides.
The "what auth library" question
Every Next.js project starts with this. Every senior engineer has an opinion. Most opinions are wrong because they generalize.
The right answer depends on three things: your team's compliance needs, your willingness to operate auth infrastructure, and how many auth providers you actually need to support.
After shipping auth on 10+ Next.js production apps in the last 18 months, here's the decision framework I use, with the foot-guns I tripped over on each path.
Option 1: NextAuth (Auth.js v5)
The default. Almost every Next.js app starts here.
Strengths:
Weaknesses:
Pick when:
Option 2: Clerk
The hosted option. Beautifully integrated.
Strengths:
Weaknesses:
Pick when:
Option 3: Custom JWT
Roll your own. Less common in 2026, but the right answer sometimes.
Strengths:
Weaknesses:
Pick when:
Specific recipes that work
MERN SaaS, B2B, under 10K users
NextAuth v5 plus Postgres adapter (Prisma or Drizzle). Magic links plus Google OAuth. Database sessions. Add 2FA at the application layer when needed. Estimated effort: 1-2 days for v1, 1 week for production polish.
MERN SaaS, B2B, growth-stage
Clerk. Pay the 25 dollars per month, get organizations plus RBAC plus MFA plus audit logs for free. Skip the build vs buy debate. Estimated effort: 4-8 hours total.
Consumer mobile app with Next.js backend
NextAuth v5 with JWT mode plus your custom email provider. The mobile app holds the access token, refreshes via your API. Estimated effort: 2-3 days.
Web3 dApp where users connect wallets
Custom JWT with SIWE (Sign-In with Ethereum). NextAuth v5 has a SIWE provider but it's not as polished as a hand-rolled version. I usually roll a custom one here because the claims structure matters. Estimated effort: 1 week for v1.
The gotchas
What bit me on each path:
NextAuth gotcha
Session callbacks run on every request. If you put expensive DB queries in your session callback (to enrich claims), every page load triggers them. Memoize aggressively or move to JWT-only mode.
Clerk gotcha
Webhook delivery for user events. Clerk fires webhooks when users sign up, update, or delete. If your DB lives separately, you need a webhook handler to sync. Easy to forget; hard to debug when out of sync.
Custom JWT gotcha
Refresh token rotation under concurrent requests. If two requests fire simultaneously with the same refresh token, naive implementations issue two new tokens and invalidate one. The user gets logged out. Mutex per refresh token solves it.
My defaults in 2026
| Project type | Auth |
|---|---|
| MERN SaaS (B2B) | NextAuth v5 if cost-sensitive, Clerk if speed matters |
| Consumer app | NextAuth v5 |
| Web3 or wallet-based | Custom JWT with SIWE |
| Enterprise SAML | WorkOS or Clerk B2B |
| Internal tool or admin | NextAuth v5 with email provider only |
TL;DR
If you're starting a Next.js project and want a senior to architect auth correctly the first time, contact me.
You might also like
Real-Time Apps with Next.js Server Actions and WebSockets in 2026
When Server Actions are enough, when you need a WebSocket layer, and how to wire Pusher / Soketi / Ably into a Next.js 14 App Router project without breaking SSR.
React Server Components in Next.js 14: Production Patterns That Work
When to use Server Components vs Client Components in Next.js 14, the patterns that survive production, and the foot-guns I keep tripping over after shipping 8+ App Router projects.
Next.js App Router vs Pages Router: Lessons From 12 Project Migrations
What changes, what breaks, what to migrate first, and what to leave alone. Hard-earned migration lessons from moving 12 client projects from Pages Router to App Router.