Clerk Auth Setup in Under 10 Minutes: 2026 Guide
Step-by-step Clerk authentication setup for Next.js apps. Real errors, production patterns, and exact configuration.
TL;DR
Clerk is a drop-in authentication platform. Install @clerk/nextjs, add environment variables, wrap your app with <ClerkProvider>, protect routes with middleware, and you're authenticating in ~10 minutes. This guide covers exact setup, real errors you'll hit, and production-ready patterns.
---
What is Clerk?
Clerk handles authentication, session management, and user identity without building it yourself. It supports passwordless auth, social logins, and multi-factor authentication out of the box.
Current stable version (verify in official docs): @clerk/nextjs v5.x (check [official Clerk docs](https://clerk.com/docs) for latest)
---
Step 1: Create a Clerk Account & Get Keys (2 mins)
1. Sign up at [clerk.com](https://clerk.com)
2. Create a new application
3. Copy your Publishable Key and Secret Key
4. Add to .env.local:
```bash NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx CLERK_SECRET_KEY=sk_test_xxxxx NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard ```
Critical: Only NEXT_PUBLIC_* keys go in frontend. CLERK_SECRET_KEY stays server-side only.
---
Step 2: Install Dependencies (1 min)
```bash npm install @clerk/nextjs ```
For other frameworks, see [Clerk integrations](https://clerk.com/docs/references/quickstarts).
---
Step 3: Wrap App with ClerkProvider (2 mins)
In app/layout.tsx:
```typescript import { ClerkProvider } from '@clerk/nextjs'; import type { Metadata } from 'next';
export const metadata: Metadata = { title: 'My App', };
export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <ClerkProvider> <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ); } ```
Error you'll see if you skip this: ``` Error: <SignIn /> can only be used within <ClerkProvider /> ```
---
Step 4: Create Authentication Routes (3 mins)
Create app/sign-in/[[...sign-in]]/page.tsx:
```typescript import { SignIn } from '@clerk/nextjs';
export default function SignInPage() { return ( <div className="flex items-center justify-center min-h-screen"> <SignIn /> </div> ); } ```
Create app/sign-up/[[...sign-up]]/page.tsx:
```typescript import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() { return ( <div className="flex items-center justify-center min-h-screen"> <SignUp /> </div> ); } ```
The [[...sign-in]] catch-all route handles Clerk's internal routing automatically.
---
Step 5: Protect Routes with Middleware (2 mins)
Create middleware.ts in your project root:
```typescript import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/api/protected(.*)', ]);
export default clerkMiddleware((auth, req) => { if (isProtectedRoute(req)) { auth().protect(); } });
export const config = { matcher: [ '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest))(?:.*))', '/(api|trpc)(.*)', ], }; ```
Error if middleware config is wrong: ``` Error: Middleware Error: Unable to verify request signature ```
This means your CLERK_SECRET_KEY isn't being read. Verify it's in .env.local (not .env).
---
Step 6: Add User Info to Frontend Components
Create app/dashboard/page.tsx:
```typescript import { UserButton, useUser } from '@clerk/nextjs'; import { redirect } from 'next/navigation';
export default function DashboardPage() { return ( <div className="p-8"> <div className="flex justify-between items-center mb-8"> <h1 className="text-2xl font-bold">Dashboard</h1> <UserButton afterSignOutUrl="/" /> </div> <p>Protected content here</p> </div> ); } ```
For client components, use the useUser() hook:
```typescript 'use client';
import { useUser } from '@clerk/nextjs';
export function WelcomeCard() { const { user, isLoaded } = useUser();
if (!isLoaded) return <div>Loading...</div>;
return ( <div> <h2>Welcome, {user?.firstName}!</h2> <p>Email: {user?.primaryEmailAddress?.emailAddress}</p> </div> ); } ```
Common error in client components: ``` Error: "useUser" must be used within <ClerkProvider /> ```
You forgot to wrap your app. Go back to Step 3.
---
Step 7: Access User in API Routes
Create app/api/protected/route.ts:
```typescript import { auth } from '@clerk/nextjs/server'; import { NextResponse } from 'next/server';
export async function GET() { const { userId, sessionId } = auth();
if (!userId) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ); }
return NextResponse.json({
message: Hello, user ${userId},
sessionId,
});
}
```
---
Production Checklist
✓ Environment variables: Production keys (not test keys) in .env.production
✓ CORS: If your frontend is on a different domain, configure in Clerk dashboard
✓ Custom domain: Optional—set up custom auth domain for brand consistency
✓ Session timeout: Verify against your security requirements in Clerk settings
✓ Logout behavior: Test that afterSignOutUrl works on all routes
---
Debugging Tips
If users see a blank sign-in page:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is correctIf middleware redirects to /sign-in unexpectedly:
createRouteMatcher correctlyauth().protect() isn't being called on public routesIf useUser() returns null after login:
<ClerkProvider> wraps the component tree'use client')---
Related Guides
[Advanced session management](/?guide=clerk-sessions) [Multi-tenant SaaS with Clerk](/?guide=saas-auth)
---
What am I missing?
Have you run into setup issues we didn't cover? Custom claims, role-based access, or integration with external databases? Drop your experience in the comments—this guide improves with real feedback from readers shipping production apps.