Skip to content
Next.js+Clerk Auth
Stack Integration

Next.js + Clerk Auth Integration Guide

Clerk provides complete user management for Next.js App Router — hosted sign-in UI, session management, and organization support — with middleware that protects routes in a single configuration file.

Use Cases
  1. Protected routes in Next.js App Router using Clerk middleware
  2. Server Components accessing the current user without additional API calls
  3. Multi-tenant organization management with Clerk Organizations
  4. Social login (Google, GitHub, Apple) added without custom OAuth implementation
Implementation

Install @clerk/nextjs and wrap the root layout with <ClerkProvider>. Configure middleware.ts using Clerk's authMiddleware to define public routes and protect everything else by default. In Server Components, use auth() from @clerk/nextjs/server to access the user ID without a client round-trip. For multi-tenant apps, Clerk Organizations provide a built-in org switcher and per-org roles — pair with Supabase RLS using the Clerk user ID as the tenant identifier.

In detail

How the pieces connect

Clerk runs as a hosted identity service; your Next.js app holds no password database. The flow has three runtime surfaces. First, <ClerkProvider> in the root layout hydrates the client with the active session and exposes hooks like useUser() and useAuth(). Second, clerkMiddleware() in middleware.ts reads the __session cookie on every matched request at the edge, before a route renders, and can short-circuit unauthenticated traffic. Third, Server Components and Route Handlers call auth() from @clerk/nextjs/server, which returns userId, sessionId, and orgId from the verified JWT — no client round-trip and no extra fetch to Clerk's API for the common case. The session token is a short-lived JWT signed by Clerk; the middleware refreshes it transparently. Because auth() reads the request context, it only works inside the App Router request lifecycle, not in arbitrary module scope.

Production gotchas

The matcher in middleware.ts is the usual source of bugs. The default Clerk matcher skips Next.js internals and static files; if you broaden it, you can accidentally run auth on _next assets or, worse, leave an API route uncovered. Mark public routes explicitly with createRouteMatcher and call auth.protect() for everything else — silent omissions fail open. Second, auth() throws or returns a null userId outside a request scope, so don't call it in layout module top-level or in a cached function without headers() access. Third, set CLERK_SECRET_KEY and NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY per environment — preview deploys need their own instance keys, and a production key in a preview leaks real sessions. Finally, Server Actions still need an explicit auth() check; middleware does not automatically guard them since they POST to the same route.

Multi-tenant security with Supabase RLS

When you pair Clerk Organizations with Supabase, the tenant boundary lives in the database, not the app. Mint a Supabase-compatible JWT from Clerk (Clerk's JWT templates let you inject sub as the user ID and a custom org_id claim), then write Row Level Security policies that read those claims via auth.jwt() ->> 'org_id'. The rule is that the client never sends the tenant ID as a trusted value — RLS derives it from the verified token, so a tampered request can't read another org's rows. Use Clerk's has() helper or the orgRole from auth() to gate writes in the app layer too, but treat that as defense in depth, not the boundary. Keep the Supabase service-role key server-only; it bypasses RLS entirely and should never reach a Client Component or the browser bundle.

When this combo fits — and when it doesn't

Clerk plus Next.js is a strong fit when you want hosted sign-in UI, social login, and organization/role management without building and maintaining auth yourself, and when most of your app is the App Router. The middleware-first model is genuinely low-config for protected dashboards and B2B multi-tenant SaaS. It fits less well if you need full control over the auth UI and data residency, if your stack is mostly serverless functions outside Next.js, or if you're cost-sensitive at high monthly-active-user counts — Clerk bills per MAU and that scales with growth. If you only need a session cookie and a single user table, a lighter library or framework-native auth may be enough. Check current Clerk pricing tiers against your projected MAU before committing, since the per-user model is the main trade-off.

Other integration guidesView all →
Related

Need this built?