Clerk Auth Setup in Under 10 Minutes: 2026 Guide
Production-ready Clerk authentication setup with exact code patterns, real error messages, and step-by-step walkthrough for indie hackers.
TL;DR
Clerk handles auth in minutes: create project, install SDK, add middleware, wrap your app. Real setup takes 8-12 minutes. We'll cover exact versions, console errors you'll hit, and production patterns.
---
Why Clerk?
Clerk abstracts OAuth, passwords, MFA, and session management. No token juggling, no database user tables to maintain. For indie hackers shipping fast, it's a significant time win.
Current pricing (verify in official docs): Free tier supports ~500 monthly active users with full features.
---
Prerequisites
node --version)---
Step 1: Create Clerk Project (2 minutes)
1. Go to [clerk.com](https://clerk.com)
2. Sign up or log in
3. Create new application → choose "Next.js" template (or your framework)
4. You'll receive:
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
- CLERK_SECRET_KEY
Save these immediately. You cannot view the secret key again without regenerating.
---
Step 2: Install Dependencies (1 minute)
```bash npm install @clerk/nextjs@latest ```
Verify installed version:
```bash npm list @clerk/nextjs ```
As of 2026, @clerk/nextjs v6+ is standard. If you get v5.x, run:
```bash npm install @clerk/nextjs@6.0.0 --force ```
---
Step 3: Add Environment Variables (1 minute)
Create .env.local in your Next.js root:
```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your_actual_key_here CLERK_SECRET_KEY=sk_test_your_actual_secret_here 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 ```
Do NOT commit these to git. Add to .gitignore:
```gitignore .env.local .env*.local ```
---
Step 4: Wrap App with ClerkProvider (2 minutes)
Edit 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> ); } ```
Common error 1:
``` Error: Could not find Clerk instance in React context. Make sure your app is wrapped with <ClerkProvider> ```
This means ClerkProvider isn't wrapping your component tree. Move it to the root layout.
---
Step 5: Add Middleware (1 minute)
Create middleware.ts at project root (same level as app/):
```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|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest))(?:.*))/', '/(api|trpc)(.*)', ], }; ```
This protects /dashboard and /api/protected/* routes. Unauthenticated users redirect to your NEXT_PUBLIC_CLERK_SIGN_IN_URL.
---
Step 6: Create Sign-In/Sign-Up Pages (2 minutes)
Create app/sign-in/[[...sign-in]]/page.tsx:
```typescript import { SignIn } from '@clerk/nextjs';
export default function SignInPage() { return ( <div style={{ display: 'flex', justifyContent: 'center', marginTop: '50px' }}> <SignIn /> </div> ); } ```
Create app/sign-up/[[...sign-up]]/page.tsx:
```typescript import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() { return ( <div style={{ display: 'flex', justifyContent: 'center', marginTop: '50px' }}> <SignUp /> </div> ); } ```
Note the [[...sign-in]] and [[...sign-up]] dynamic segments—these catch all route variations Clerk uses.
---
Step 7: Protect Your Dashboard (1 minute)
Create app/dashboard/page.tsx:
```typescript import { auth } from '@clerk/nextjs/server'; import { redirect } from 'next/navigation';
export default async function DashboardPage() { const { userId } = await auth(); if (!userId) { redirect('/sign-in'); }
return ( <div> <h1>Welcome back, {userId}!</h1> <p>You are authenticated.</p> </div> ); } ```
Common error 2:
``` TypeError: Cannot read property 'userId' of null ```
You're accessing auth() before middleware has validated the session. Either:
1. Ensure middleware.ts is present and active
2. Move auth() call inside a try/catch
3. Use <SignedIn> and <SignedOut> components client-side
---
Step 8: Add User Menu (1 minute)
Create components/user-button.tsx:
```typescript 'use client';
import { UserButton } from '@clerk/nextjs';
export function UserMenu() { return <UserButton afterSignOutUrl="/" />; } ```
Use in layout or nav:
```typescript import { UserMenu } from '@/components/user-button';
export default function Header() { return ( <header> <h1>My App</h1> <UserMenu /> </header> ); } ```
Common error 3:
``` Error: useAuth must be used within <SignedIn> or similar context ```
Mark the component 'use client' at the top. Clerk components require client-side rendering.
---
Testing Locally
```bash npm run dev ```
Visit http://localhost:3000/dashboard. You should redirect to /sign-in. Create an account and verify the flow.
---
Production Checklist
1. Verify in official docs: Update environment keys for production instance (not test) 2. Add [API key rotation](https://clerk.com/docs/security) to your security process 3. Enable [CORS](/?guide=cors) for cross-origin requests if using separate frontend 4. Test [sign-out](/?guide=logout) flow 5. Configure [custom domains](https://clerk.com/docs/deployments/clerk-domain) if needed
---
What am I missing?
Have you hit different errors? Using a framework Clerk doesn't officially support? Found a faster setup? Comment below with your experience. This guide improves with real-world feedback.
---