What Is NextAuth.js and Why SpeedMVPs Uses It
NextAuth.js is an open-source authentication library for Next.js that handles OAuth flows, session management, JWT or database-backed sessions, and provider-specific user data normalisation. Version 5 (Auth.js) extends support beyond Next.js to other frameworks including SvelteKit, SolidStart, and Express, while maintaining the familiar configuration pattern that Next.js developers know. SpeedMVPs reaches for NextAuth in specific situations where managed auth services are not the right fit. The most common is when a client's GDPR compliance assessment concludes that user authentication data must remain in infrastructure the client controls, with no third-party auth service holding session tokens, user identities, or OAuth refresh tokens. This is a real requirement in certain NHS-adjacent deployments and regulated financial services contexts where the data classification of the user population precludes third-party SaaS for identity management. NextAuth is also the right choice for products with custom credential requirements that managed services do not support: authentication against an existing LDAP directory, integration with a legacy identity system, or a custom OTP flow that requires bespoke server-side logic. When the authentication logic is genuinely custom, building it in NextAuth gives full control without the constraints of a managed service's extension model. The tradeoff is clear: NextAuth requires you to build and maintain the UI components, implement session storage, handle token rotation, and manage the edge cases that managed services handle silently. For most AI MVPs, SpeedMVPs recommends Clerk unless there is a specific requirement that justifies the additional implementation work.
Setting Up NextAuth.js in a Production AI Project
NextAuth.js v5 (Auth.js) setup in Next.js App Router follows a specific pattern. Here is the production configuration SpeedMVPs uses. First, install next-auth. Create an auth.ts configuration file at the project root. Define your providers array, session strategy, and any callbacks you need. Export the handlers, signIn, signOut, and auth functions from this file. Second, create the route handler. In your App Router project, add app/api/auth/[...nextauth]/route.ts that exports the GET and POST handlers from your auth.ts configuration. Third, configure OAuth providers. Each provider requires a client ID and client secret obtained from the provider's developer console. Set these as environment variables (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, etc). Configure the authorised redirect URI in each provider's console: your production domain's /api/auth/callback/[provider] route. Fourth, configure session persistence. JWT sessions are the simpler option (session data stored in a signed cookie, no database required for session lookup). Database sessions (using a NextAuth adapter for your database) allow session invalidation from the server but require a database query on every authenticated request. For most AI MVPs, JWT sessions with a reasonable token expiry (24 to 72 hours) are the right choice. Fifth, if using database sessions or storing user data (required for linking accounts to application data), add a database adapter. NextAuth provides adapters for Drizzle, Prisma, Supabase, and other ORMs. The adapter handles creating user rows, session rows, and account rows on first sign-in. Sixth, protect routes using the auth() function in server components and middleware. In middleware.ts, export the auth() function from NextAuth's middleware helper and configure the matcher to protect application routes. Seventh, configure the AUTH_SECRET environment variable - a random 32-byte string used to sign JWT tokens and CSRF tokens. Generate it with openssl rand -base64 32 and store it in your secret manager.
Key Features and Capabilities
OAuth provider support covers 80+ providers with pre-built configurations for Google, GitHub, Microsoft, Apple, LinkedIn, and others. Each provider handles the OAuth 2.0 or OIDC flow, token exchange, and user profile normalisation. Adding a new provider is a matter of adding it to the providers array with the appropriate credentials. Custom credential providers allow implementing any authentication logic as a NextAuth provider. The Credentials provider accepts an authorize function that takes the submitted credentials and returns a user object or null. This is how you implement email/password authentication against your own user database, OTP verification, or authentication against legacy systems. Callback functions intercept and modify the authentication flow at multiple points. The jwt callback runs when a JWT is created or updated, allowing you to add custom claims (like the user's subscription tier or organization ID) to the token that will be available in every authenticated session. The session callback controls what data from the JWT is included in the client-side session. The signIn callback allows blocking or redirecting sign-ins based on custom logic (for example, blocking sign-ups from non-allowlisted email domains). The useSession hook in client components and the auth() function in server components and route handlers provide consistent access to the session data throughout the application. For AI API routes, auth() validates the session token and returns the user context without a network round-trip. NextAuth's database adapter pattern stores user, account, and session data in your application database. This gives you full ownership of the user data (no third party holds it), enables complex queries against your user base, and allows custom user fields beyond what OAuth providers return. Email provider support enables magic link authentication - users enter their email and receive a sign-in link. This requires a transactional email service (Resend, SendGrid, or Nodemailer) and a database adapter for verification token storage.
Real-World Workflow: NextAuth.js in an AI MVP
An example from SpeedMVPs: an AI document analysis tool for a UK NHS-adjacent healthcare organisation. The client's IG (Information Governance) team required that user authentication data - email addresses, session tokens, OAuth tokens - stay within the client's own AWS infrastructure and not be processed by any third-party SaaS service. NextAuth was the appropriate choice. The implementation used Google OAuth for authentication (NHS staff have Google Workspace accounts), with NextAuth handling the OAuth flow and a Drizzle adapter storing users, accounts, and sessions in RDS PostgreSQL in eu-west-2. All authentication data remained within the client's AWS infrastructure. Custom jwt callback added the user's role (clinician, admin, or viewer) to the JWT token from the database, so every API route could authorise requests without a database lookup for role information. The session callback exposed the role to client components for UI-level permission checks. Route protection used NextAuth middleware wrapping all routes under /dashboard and /api/ai. The middleware ran in Vercel's Edge Runtime, validating the JWT and redirecting unauthenticated users to /sign-in in under two milliseconds. No third-party service was involved in session validation - the JWT was verified with the AUTH_SECRET stored in AWS Secrets Manager, accessed by the Edge Middleware via a Vercel environment variable. GDPR compliance documentation noted only two data processors for authentication: Google (as OAuth provider, under Google's DPA) and AWS RDS (as the session store, under the client's existing AWS DPA). The client's IG team approved the implementation within 48 hours - significantly faster than approval processes for third-party auth services they had not previously vetted.
Cost and Pricing Considerations
NextAuth.js is completely free and open-source under an ISC licence. There is no licensing cost at any scale. The costs associated with a NextAuth implementation are infrastructure (the database for session storage if using database sessions, or negligible JWT signing costs otherwise) and engineering time. The engineering time cost is the significant factor. A production-ready NextAuth implementation with multiple OAuth providers, email magic links, database sessions, and proper UI components takes three to five working days for an experienced engineer. A comparable Clerk integration takes one to two days. For a two to three week AI MVP delivery, that two to three day difference is material. For bootstrapped founders, the zero licensing cost of NextAuth is genuinely attractive when compared to Clerk's USD 25 per month Pro plan. The breakeven calculation: if the additional engineering time costs more than roughly two years of Clerk Pro subscription (in your cost of engineering time), Clerk is financially rational even for cost-sensitive founders. For most funded or revenue-generating products, it is. Maintenance cost is ongoing with NextAuth. Dependency updates, Auth.js v5 migration, new provider configurations, and bug fixes in the auth implementation require engineering time that the Clerk platform would have handled automatically. For resource-constrained teams, this maintenance overhead is a real cost that does not appear in the upfront comparison.
Alternatives to NextAuth.js
Clerk is the primary managed alternative, covering most auth requirements with pre-built UI components, B2B organisation management, and SSO support. For AI SaaS MVPs without strict self-hosting requirements, Clerk is SpeedMVPs' default choice over NextAuth. Supabase Auth provides self-hosted authentication within the Supabase platform. For products already on Supabase, Supabase Auth is a natural fit, tightly integrated with Row Level Security and offering similar capabilities to NextAuth for basic auth flows. It lacks NextAuth's flexibility for custom credential providers and complex callback logic. Better Auth is a newer open-source authentication library for TypeScript applications, compatible with Next.js, Astro, and other frameworks. It takes a more type-safe approach than NextAuth with a schema-based configuration and is worth evaluating for teams starting new projects who find Auth.js's configuration model verbose. Passport.js is the classic Node.js authentication middleware and remains relevant for Express-based backends that need flexible authentication. For Next.js App Router applications, NextAuth is the more idiomatic choice, but Passport.js is appropriate for separate Node.js API servers requiring custom auth middleware. For teams building AI products on non-Next.js stacks (FastAPI, Django REST Framework, or Express), the managed auth service options (Auth0, Cognito, Clerk where available) are more directly applicable than NextAuth, which is optimised for the Next.js runtime.