Clerk Auth Setup in 10 Minutes: 2026 Guide
Get Clerk authentication running in your Next.js app fast. Code examples, common errors, and production patterns included.
TL;DR
Clerk handles auth so you don't have to. Install the SDK, grab API keys from the dashboard, wrap your app with <ClerkProvider>, protect routes with middleware, and you're live. ~10 minutes for a working setup.
---
Why Clerk?
If you're building an indie product, you know the auth tax is real. Clerk abstracts away password hashing, session management, OAuth flows, and MFA. You get a managed solution without managing a user database (unless you want to). The free tier covers most indie launches.
Current pricing (verify in official docs): Free tier includes 5,000 monthly active users. Paid tiers start around $25/month. [Official pricing](https://clerk.com/pricing)
---
Prerequisites
---
Step 1: Create a Clerk Application (2 min)
1. Go to [Clerk Dashboard](https://dashboard.clerk.com) 2. Click "Create application" 3. Choose your auth strategy (Email + Password, Google OAuth, etc.) 4. Copy your Publishable Key and Secret Key
These are sensitive—treat CLERK_SECRET_KEY like a database password.
---
Step 2: Install and Configure (3 min)
Install the SDK
```bash npm install @clerk/nextjs ```
Verify version compatibility: @clerk/nextjs v5.x is current (verify in official docs for latest).
Set Environment Variables
Create .env.local:
```bash NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... 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=/onboarding ```
Note: Keys prefixed with NEXT_PUBLIC_ are exposed to the browser—that's intentional for Clerk's publishable key.
---
Step 3: Wrap Your App (2 min)
Update 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> ); } ```
Production pattern: Don't pass appearance props here. Configure branding in the Clerk Dashboard or create a separate theme provider.
---
Step 4: Add Auth Routes (2 min)
Clerk provides pre-built UI components. Create sign-in and sign-up pages:
app/sign-in/[[...index]]/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> ); } ```
app/sign-up/[[...index]]/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 [[...index]] catch-all routing lets Clerk handle multi-step flows internally.
---
Step 5: Protect Routes with Middleware (1 min)
Create middleware.ts in your project root:
```typescript import { authMiddleware } from '@clerk/nextjs';
export default authMiddleware({ publicRoutes: ['/', '/pricing', '/blog(.*)'], ignoredRoutes: ['/api/webhooks/clerk'], });
export const config = { matcher: [ '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?))(?:.*)|api|trpc)(.*)', ], }; ```
Production pattern: List all public routes explicitly. Anything not listed requires authentication.
---
Step 6: Access User Data (Bonus)
In any Server Component:
```typescript import { auth, currentUser } from '@clerk/nextjs';
export default async function Dashboard() { const { userId } = await auth(); const user = await currentUser();
if (!userId) { return <div>Not authenticated</div>; }
return ( <div> <p>Welcome, {user?.firstName}</p> <p>Email: {user?.primaryEmailAddress?.emailAddress}</p> </div> ); } ```
In Client Components, use the useAuth() hook:
```typescript 'use client';
import { useAuth } from '@clerk/nextjs';
export function UserNav() { const { userId, isSignedIn } = useAuth();
if (!isSignedIn) return <a href="/sign-in">Sign In</a>;
return <span>User ID: {userId}</span>; } ```
---
Common Errors You'll See
1. Missing Publishable Key
``` Error: The Clerk publishable key is missing. Make sure that the NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY environment variable is set. ```
Fix: Verify .env.local exists and you've restarted your dev server after adding variables.
2. Secret Key Exposed in Browser
``` Warning: The Clerk secret key was found in your public environment variables. Keep your secret key in server-side environment variables only. ```
Fix: Remove NEXT_PUBLIC_ prefix from CLERK_SECRET_KEY. Never expose it.
3. Middleware Not Intercepting Routes
``` Error: Page ... is not protected. User can access it without authentication. ```
Fix: Ensure your middleware.ts matcher regex covers your protected routes. Test with console.log() in middleware to debug.
---
Verification Checklist
.env.localClerkProvider wraps root layout---
Next Steps
For production, review [Clerk's security best practices](https://clerk.com/docs/security/overview) (verify in official docs).
---
Related Guides
---
What am I missing?
Have you hit snags with Clerk setup? Found version incompatibilities? Set it up differently? Drop corrections and real-world tips in the comments below—let's build a better resource together.