Skip to main content

Authentication Setup in Next.js Boilerplates 2026

·StarterPick Team
Share:

TL;DR

  • Clerk is the fastest to ship: 11 React hooks, prebuilt UI components, deepest Next.js integration — best for moving fast without worrying about auth infrastructure
  • Auth.js (NextAuth v5) is the ecosystem standard: 2.5M+ weekly downloads, extensive provider support, fully self-hosted — best for cost-sensitive or self-hosted setups
  • Better Auth is the type-safe challenger: batteries-included (2FA, passkeys, organizations), self-hosted, and gaining momentum in 2025–2026
  • The 3-tier recommendation: self-hosted OAuth → Auth.js, managed → Clerk, type-safe self-hosted → Better Auth
  • All major auth libraries now support Next.js App Router natively — Pages Router support is in maintenance mode

Key Takeaways

  • Auth.js (NextAuth) has ~2.5M weekly npm downloads — it is the established default in the ecosystem
  • Clerk charges per monthly active user: free tier covers 10,000 MAU, paid starts at $25/month for 10,001+
  • Better Auth ships with organizations, RBAC, 2FA, passkeys, and impersonation out of the box — all free and self-hosted
  • Route protection in 2026 must use Next.js middleware, not component-level guards — all three libraries provide middleware helpers
  • Database session storage: Clerk stores sessions in Clerk's infrastructure; Auth.js and Better Auth store in your database

Why Authentication Complexity Has Increased

Authentication in 2026 is harder than it was in 2022 — not because the concepts have changed, but because user expectations have. In 2022, implementing Google and GitHub OAuth plus email/password was sufficient for most SaaS products. Today, users expect passkeys, magic links, multi-factor authentication, social login with half a dozen providers, and seamless team/organization management.

At the same time, the regulatory environment has tightened. GDPR enforcement has matured, and handling auth incorrectly — storing passwords in plain text, using weak session tokens, failing to implement CSRF protection — carries real legal and reputational risk. The shift toward managed auth providers (Clerk, Auth0, WorkOS) reflects this: for many teams, paying someone to solve authentication correctly is cheaper than solving it yourself.

But managed auth providers have trade-offs: vendor dependency, per-MAU pricing that becomes significant at scale, and reduced control over the data. The 2026 landscape offers genuine choices, and the right one depends on your specific constraints.

This guide covers the three primary options that dominate modern Next.js boilerplates and how to evaluate them for your project.


Auth.js (NextAuth v5): The Ecosystem Standard

Auth.js is the direct evolution of NextAuth, the library that has been the community standard for Next.js authentication since 2020. Version 5 rewrote the internals for App Router compatibility while maintaining backward compatibility with the extensive provider ecosystem.

With approximately 2.5 million weekly npm downloads, Auth.js has the most community support of any Next.js auth library. If you encounter a specific authentication pattern — OAuth with account linking, email verification flows, JWT customization, multi-provider handling — there is almost certainly a documented example or Stack Overflow answer for Auth.js.

The core setup creates an auth.ts configuration file that exports the handlers, sign-in/sign-out functions, and session accessor used throughout the application. The handler is registered as a catch-all API route that processes all auth callbacks.

Middleware protection is handled by exporting the auth function directly as the middleware export. The configuration object's callbacks.authorized function determines which requests are allowed. Routes not in the matcher config are unprotected; routes in the matcher are gated by the authorized callback.

Strengths of Auth.js for boilerplates:

The self-hosted model means sessions are stored in your database and data never leaves your infrastructure. For compliance-sensitive applications, healthcare, or enterprise deployments, this is often required. Auth.js stores sessions using a database adapter — Prisma, Drizzle, and raw SQL adapters are all available.

The provider ecosystem covers over 50 OAuth providers, including niche ones like Discord, Spotify, Twitch, and dozens of enterprise identity providers. If you need a provider that Clerk does not natively support, Auth.js almost certainly has it.

Limitations:

Auth.js does not include organization/team management out of the box. Building multi-tenancy on top of Auth.js means implementing invitation flows, role assignment, and permission checking yourself. This is a significant amount of code that paid boilerplates and managed providers have already built.

For a detailed comparison of Auth.js against competing approaches: AuthJS v5 vs Lucia v3 vs Better Auth 2026.


Clerk: Managed Auth With Maximum Developer Productivity

Clerk is the managed authentication platform designed specifically for Next.js. It provides a complete suite of prebuilt UI components, React hooks, and server utilities that handle authentication without requiring you to build any UI or auth logic yourself.

The depth of Clerk's Next.js integration is its primary differentiator. The <SignIn /> and <SignUp /> components render polished, accessible authentication forms that work immediately — no styling, no logic, no form handling required. The <UserButton /> component renders the user's profile picture with a dropdown that includes sign-out, profile management, and organization switching. The <OrganizationSwitcher /> handles the full multi-tenant organization experience.

Clerk's eleven React hooks provide read access to session state, user data, and organization context from any component. The useUser() hook returns the current user profile. The useOrganization() hook returns the currently active organization and its members. The useAuth() hook provides the session token for making authenticated API requests.

Route protection through Clerk's middleware uses a route matcher pattern: you define which routes require authentication, and the middleware redirects unauthenticated users before any page rendering occurs. All routes are public by default — you opt in to protection.

Pricing reality check:

Clerk's free tier is genuinely generous at 10,000 monthly active users. For most startups in the zero-to-PMF stage, this is sufficient. The paid tier starts at $25/month, which covers up to 10,001–100,000 MAU with the first 10,000 still free.

Where costs become significant is at scale. At 100,000 MAU, Clerk costs roughly $250/month. At 1 million MAU, you are looking at a substantial recurring cost that may make migrating to Auth.js or a custom solution worth the engineering investment.

Organizations and B2B features require the paid tier. If your product requires team accounts — and most B2B SaaS does — factor Clerk's organizational features into the total cost of ownership from day one.

When Clerk is clearly the right choice:

For pre-revenue or early-stage products where engineering velocity matters more than infrastructure cost, Clerk is hard to beat. The difference between "Auth is done" and "Auth is mostly done but edge cases keep surfacing" is worth $25/month to most founders. For a comparison with enterprise-tier alternatives: Clerk vs Auth0 vs WorkOS B2B SaaS Auth 2026.


Better Auth: The Self-Hosted Features-First Alternative

Better Auth emerged in 2024 as a direct response to the gap in the market: developers who want self-hosted auth but need the features that Clerk provides at a paid tier. It is open source, completely free, and ships with a feature set that exceeds Clerk's free tier.

The design philosophy is type-safety first. Better Auth's TypeScript types are generated from your configuration — if you enable the organizations plugin, you get typed methods for creating organizations, inviting members, and checking permissions. If you enable passkeys, you get typed passkey methods. The type system prevents calling methods for features you have not enabled.

Better Auth ships with a plugin architecture where each feature is a discrete plugin:

  • Email and password authentication is core
  • OAuth via any provider (identical interface regardless of provider)
  • Two-factor authentication (TOTP via authenticator app)
  • Passkeys via WebAuthn
  • Organization management (create orgs, invite users, assign roles)
  • Role-based access control with fine-grained permissions
  • User impersonation for admin and support use cases
  • Session management with device tracking and selective revocation

All of this is free and runs in your infrastructure. The closest comparison is Clerk at its paid tier — but with your data in your database.

The trade-off: community maturity.

Better Auth is newer (2024) than Auth.js (2019) and Clerk (2021). The community is growing but smaller. There are fewer boilerplate examples, fewer documented edge cases, and fewer Stack Overflow answers. When you encounter an unusual pattern, you may need to read the source code rather than finding a community answer.

For projects that can accept some early-adopter risk in exchange for significant feature breadth at zero cost, Better Auth is compelling. Best Boilerplates Using Better Auth 2026 covers the starter kits that have already integrated it.


Feature Comparison

FeatureClerkAuth.jsBetter Auth
OAuth providers30+50+Any (custom)
Email + password
Magic links
Two-factor auth✓ (paid)Plugin✓ (free)
PasskeysPlugin✓ (free)
Organizations/teams✓ (paid)DIY✓ (free)
Role-based access control✓ (paid)DIY✓ (free)
User impersonation✓ (paid)DIY✓ (free)
Self-hosted
Prebuilt UI componentsOptional
App Router support
Free MAU limit10,000UnlimitedUnlimited

The Critical Rule: Middleware-First Protection

The most common authentication mistake in Next.js App Router applications is implementing route protection at the component level rather than at the middleware level. This mistake is easy to make because it looks correct — a if (!session) redirect('/login') check in a Server Component prevents the page from rendering for unauthenticated users. But it does not prevent the server from executing the Server Component's logic, including any database queries, before the redirect fires.

Correct route protection runs in Next.js middleware, which intercepts the request before any component rendering occurs. Each of the three major auth libraries provides a middleware-first protection API. The implementation looks different for each library — Auth.js exports its auth function directly as middleware, Clerk uses clerkMiddleware with a route matcher, Better Auth checks the session in a custom middleware function — but the pattern is identical: check authentication status before rendering, not during rendering.

For pages that must be fast, middleware-level protection has an additional benefit: unauthenticated requests are redirected before any RSC rendering work happens on the server, reducing wasted compute and improving response times for protected pages.


Choosing Based on Your Boilerplate Context

The right auth library depends on factors specific to your project rather than abstract quality comparisons. All three options are production-ready and used by companies at scale.

Choose Auth.js when:

  • Cost sensitivity at scale matters — Auth.js has no per-user pricing
  • You need a specific OAuth provider from the extended ecosystem
  • Data residency requirements prevent using managed services
  • You want the largest community for troubleshooting

Choose Clerk when:

  • Engineering velocity is the primary constraint
  • You need organizations/team management in the next sprint
  • Expected MAU stays manageable relative to pricing
  • The prebuilt UI components align with your design requirements

Choose Better Auth when:

  • You need organizations and RBAC without per-user pricing
  • Strong TypeScript correctness is a team value
  • You can accept lower community support in exchange for feature breadth
  • Early-adopter risk is acceptable for your project

For a ranking of boilerplates by their authentication implementation quality and completeness: NextAuth vs Clerk vs Supabase Auth 2026 evaluates the major options across a consistent set of criteria.


Why Authentication Is the Hardest Problem in SaaS Boilerplates

Most developers estimate their authentication work based on what they can see: a login form, a signup form, and a logout button. The visible surface of authentication is small. The invisible complexity underneath it is enormous, and underestimating it is one of the most common reasons SaaS projects slip their launch timeline.

Consider what a production authentication system actually needs to handle. Email verification is the first expansion beyond the obvious. Do you verify email on signup before granting access, or do you allow access immediately and require verification before accessing paid features? Each choice has different implementation requirements, different edge cases when users never verify, and different support implications when a user claims they never received the verification email. The verification email itself requires a transactional email provider, a reliable link generation and storage strategy, expiry logic, and a resend flow.

Password reset is similarly deceptively complex. The flow seems simple — user enters email, receives a link, clicks it, enters a new password — but each step has sharp edges. The reset link must expire (but how long is reasonable?). It must be single-use (what happens if the user clicks it twice?). The email must go to a confirmed address, not one that an attacker registered to intercept the reset. The link must contain a token that cannot be guessed and must be invalidated after use. None of this is difficult individually, but implementing all of it correctly under time pressure is where mistakes happen.

Session management surfaces complexity that most developers only encounter after launch. What should happen when a user logs in on five different devices simultaneously? Should the oldest session expire? Should there be a maximum concurrent session count? What does "log out everywhere" mean in your system? If you are using JWTs, logging out everywhere requires either a token revocation list (adding server state to a stateless system) or waiting for tokens to expire naturally. If you are using database sessions, you delete all session records for that user. The implementation choice you made for session storage determines how hard "log out everywhere" is to build.

Account deletion is a GDPR requirement in European markets, and it has a surprising amount of implementation surface. Deleting an account means deciding what to do with every piece of data the user created — do posts and comments get deleted, anonymized, or preserved with a placeholder attribution? Active subscriptions must be cancelled before the account is deleted. Any pending email sequences (onboarding emails, drip campaigns) must be cancelled. Connected OAuth accounts must be disconnected. The deletion must be auditable to demonstrate GDPR compliance if requested.

Security features that users do not see are the ones that protect them when they are not paying attention. Suspicious login detection — flagging logins from unusual geographies or devices — requires storing location metadata on sessions. Account lockout after repeated failed login attempts requires tracking failure counts per account. Brute force protection requires rate limiting at the authentication endpoint level, not the application level.

None of this is impossible to build. Every feature has been built many times before. But building all of it correctly, to production quality, without gaps that become security incidents or GDPR violations, takes substantially longer than first estimates suggest. The most common developer regret in SaaS authentication is "I thought I could build this faster than setting up a library, and I was wrong." Using an established authentication library — any of the three covered in this guide — means starting with all of this complexity already handled, so you can focus on the parts of your product that are actually differentiated.


Session Architecture: JWT vs Database Sessions

The decision between JWT-based sessions and database sessions is one of the foundational architectural choices in authentication setup, and it has real consequences for how your application behaves in production. Understanding the trade-offs helps you evaluate boilerplates and configure your chosen auth library correctly.

JWTs (JSON Web Tokens) are self-contained session tokens. The token itself encodes the user's identity, claims, and expiration time, cryptographically signed so the server can verify it without consulting a database. This stateless design is appealing for performance: a server that receives a JWT can validate it by verifying the signature and checking the expiration field without making any external calls. This is why JWTs are popular in distributed systems and API gateways — the token carries everything needed to authenticate the request.

The problem with JWTs is that they cannot be revoked immediately. If a user's account is compromised and you need to invalidate their session right now, you cannot — the token remains valid until its natural expiration time. You can work around this by maintaining a revocation list server-side, but at that point you have added the stateful database lookup that JWTs were meant to eliminate. You can shorten the token lifetime so compromised tokens expire quickly, but then you need a refresh token mechanism to keep legitimate users from being logged out constantly. JWTs in practice tend to be more complex than their stateless simplicity initially suggests.

Database sessions store a session record in your database and send the user a session ID (typically a cookie). On each request, the server looks up the session ID in the database, finds the associated user, and proceeds. This round-trip to the database on every authenticated request is the trade-off: it is slower than JWT validation, and it requires database availability on every request.

The advantage is complete control. To log a user out of all devices, you delete all session records with their user ID. To revoke a specific compromised session, you delete that record. To see all active sessions a user has, you query the sessions table. To enforce a maximum concurrent session count, you count and limit records. Database sessions give you precise, immediate control over authentication state.

For SaaS products, database sessions are almost always the correct choice. The database round-trip cost is minimal in practice — your application is already making database calls on most requests — and the ability to immediately invalidate a compromised session is worth it. Enterprise customers with security-conscious IT departments will ask whether you can remotely terminate sessions. With database sessions, the answer is yes and it is a one-line query. With pure JWTs, the honest answer is "only after the token expires."

Looking at which libraries use which approach: Clerk uses JWTs but builds a fast revocation layer through CDN-edge validation, giving most of the revocation benefits without the database lookup. Auth.js supports both; with a database adapter configured, it uses database sessions by default, which is the recommended configuration for production. Better Auth uses database sessions as its default — the session table is part of the core schema that Better Auth requires you to create.


Multi-Tenancy and Organization Support

If you are building a B2B SaaS product, the way your authentication library handles organizations will determine more of your architecture than almost any other decision. Most developers discover this mid-project rather than at the start, which is why organization support deserves careful evaluation before committing to a boilerplate.

The fundamental distinction is between per-user products and per-organization products. In a per-user product, each user is an independent entity: they sign up individually, have their own subscription, and interact with their own data. Billing is per-user. This model is straightforward. The auth layer needs to know who a user is, and the rest follows from that.

In a per-organization product — which describes the majority of B2B SaaS — a company signs up as a customer, and the company account contains multiple individual users with different roles. The salesperson who evaluates your product, the admin who manages billing, and the end users who use it daily are all members of the same organization. Billing attaches to the organization. Permissions exist at the organization level. Inviting new team members is a core product feature. The data that users create belongs to the organization, not the individual.

Building organization support from scratch on top of a basic auth library is one of the most underestimated tasks in SaaS development. The feature list sounds manageable: an organizations table, an invitations table, a membership join table with roles, permission checking middleware. In practice, each of these expands. The invitation system needs email delivery, link expiry, handling invitations to email addresses that have not yet signed up, and handling the case where an invitation link is clicked on a different device than expected. Role management needs to be enforceable in server components, API routes, and database-level policies consistently. The organization switcher in the UI needs to handle users who belong to multiple organizations and remember which one was active across sessions.

Clerk charges for organizations because this feature set is expensive to build and maintain correctly. The $25/month paid tier that unlocks organizations is not arbitrary pricing — it reflects the development cost of the feature. This is also why Better Auth including organizations for free is genuinely notable: you get the full invite system, role management, and organization membership handling in your own database, without a service dependency or per-user pricing.

The strategic guidance here is direct: if your product will ever support "invite your team" functionality, plan for organization support from the first commit. This is one of the most painful retrofits in SaaS development because the organization concept needs to thread through your entire data model. Every resource your users create needs an organization_id. Every query needs to be scoped to the current organization. Every permission check needs to consider the user's role within the organization. Adding this retroactively means touching every table, every query, and every API route. Building it in from the start means it is simply how your application works.


Testing Authenticated Routes

Testing is often the part of authentication setup that gets skipped in boilerplates, then becomes a problem the first time someone breaks a protected route and does not notice until it reaches production. A well-structured boilerplate includes a testing pattern for authenticated routes from the start.

The core challenge with testing authentication is that auth state is external to your application code — it lives in the auth provider, in cookies, or in database session records. Tests need a way to simulate authenticated state without going through the full browser-based login flow, which is slow and brittle as a default testing strategy.

Integration tests at the API route level are the most practical starting point. For Next.js route handlers, you can inject a test session by setting a cookie or authorization header that your auth middleware recognizes as valid in the test environment. Auth.js and Better Auth both expose session APIs that accept direct session tokens, which can be pre-generated for test users and used in test environment configurations. The approach is to set up one or more test user accounts at the start of the test suite, generate session tokens for them, and inject those tokens into requests.

Clerk provides test-specific helper tokens through its testing API. In test mode, Clerk accepts tokens generated with your test secret key, allowing you to make authenticated requests to your application without going through the Clerk UI or OAuth flows. This makes Clerk-based apps surprisingly testable despite being a managed service.

For end-to-end tests with Playwright, the recommended pattern is to handle authentication once per test suite using storageState. You log in through the actual UI once, save the resulting browser storage state (cookies, localStorage) to a file, and then load that state at the start of each test rather than logging in fresh. This approach tests the login flow itself and then reuses the authenticated state efficiently:

// playwright.config.ts
export default defineConfig({
  projects: [
    {
      name: 'setup',
      testMatch: /auth\.setup\.ts/,
    },
    {
      name: 'authenticated',
      use: { storageState: 'playwright/.auth/user.json' },
      dependencies: ['setup'],
    },
  ],
});

Testing protected API routes separately from page logic makes tests more maintainable and failure messages more useful. When a page test fails, the failure might be in the route handler, in the session validation, in the database query, or in the rendering logic. When you test the route handler directly with explicit session tokens, failures isolate to the handler behavior. When you test the session validation logic separately, you can verify that missing tokens, expired tokens, and invalid tokens each produce the correct response code. Keeping these layers separate makes the test suite a reliable diagnostic tool rather than just a binary pass/fail signal.

Pay particular attention to what happens in tests when session tokens expire. Long-running test suites can generate tokens at the start of a run that expire before the suite finishes. Design your test helpers to generate tokens with a long expiry for test environments, and document this as part of the boilerplate's testing setup so future developers understand why the test configuration differs from production.


Methodology

Based on official documentation for Clerk, Auth.js v5, and Better Auth (March 2026), npm download statistics from npmtrends.com, developer feedback from r/NextJS and indie hackers forums, pricing pages (March 2026), and hands-on testing of authentication flows in the ixartz, MakerKit, and Shipfast boilerplates.

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.