Auth & Data
Clerk Auth Setup (Next.js)
Use when adding Clerk authentication to a Next.js App Router app, protecting routes behind sign-in, or reading the signed-in user in server code. Also use when auth() throws in a route handler, a protected route lets an unauthenticated request through, or the provider and middleware disagree about which routes are public. If a request needs to know who the user is, use this skill.
1 file
Description
Use when adding Clerk authentication to a Next.js App Router app, protecting routes behind sign-in, or reading the signed-in user in server code. Also use when auth() throws in a route handler, a protected route lets an unauthenticated request through, or the provider and middleware disagree about which routes are public. If a request needs to know who the user is, use this skill.
name: clerk-auth-setup description: Use when adding Clerk authentication to a Next.js App Router app, protecting routes, or debugging why auth() throws in a route handler. Covers provider, middleware, and safe server-side user reads.
Clerk Auth Setup (Next.js App Router)
When to trigger
Adding sign in, gating a route or API behind auth, or fixing a 500 that traces back to auth() in a server context.
Setup steps
-
Install:
pnpm add @clerk/nextjs. -
Put keys in
.env.localonly, never in code:NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_... CLERK_SECRET_KEY=sk_... -
Wrap the root layout:
import { ClerkProvider } from "@clerk/nextjs"; export default function RootLayout({ children }) { return <ClerkProvider><html><body>{children}</body></html></ClerkProvider>; } -
Add
middleware.tsusingclerkMiddleware()(not the retiredauthMiddleware):import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; const isProtected = createRouteMatcher(["/dashboard(.*)", "/api/private(.*)"]); export default clerkMiddleware(async (auth, req) => { if (isProtected(req)) await auth.protect(); }); export const config = { matcher: ["/((?!_next|.*\\..*).*)", "/(api|trpc)(.*)"] };
Reading the user server-side
auth() from @clerk/nextjs/server is async: const { userId } = await auth();.
Pitfalls
- If middleware skips
clerkMiddleware()for some environments (for example dev, when keys are domain-locked to production),auth()throws instead of returning null. Wrap server reads in a helper that returnsnullwhen Clerk is not active, and call that helper from API routes. auth.protect()in middleware redirects browser requests but returns 404 for API routes. For APIs, readuserIdand return your own 401.- Do not call
auth()in a client component. UseuseAuth()/useUser()there.
Related
Added 2026-07-01. Back to the Skill Library.

Get Smarter About AI Dev
New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.