Auth & Data
Wire Clerk into a Next.js App Router app: provider, middleware, protected routes, and reading the user in server code without throwing.
1 file
Description
Wire Clerk into a Next.js App Router app: provider, middleware, protected routes, and reading the user in server code without throwing.
Adding sign in, gating a route or API behind auth, or fixing a 500 that traces back to auth() in a server context.
Install: pnpm add @clerk/nextjs.
Put keys in .env.local only, 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.ts using clerkMiddleware() (not the retired authMiddleware):
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)(.*)"] };
auth() from @clerk/nextjs/server is async: const { userId } = await auth();.
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 returns null when 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, read userId and return your own 401.auth() in a client component. Use useAuth() / useUser() there.Related
Added 2026-07-01. Back to the Skill Library.

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.