Clerk Auth Setup in Under 10 Minutes - 2026 Guide
Production-ready Clerk authentication in minutes. Real errors, exact versions, and patterns indie hackers actually use.
TL;DR
Clerk handles authentication so you don't have to. This guide gets you from zero to protected routes in ~10 minutes using current best practices. We'll cover Next.js 15+ setup, real console errors you'll hit, and production-ready code patterns.
Why Clerk?
Clerk abstracts the OAuth nightmareβsocial login, passwordless auth, user management, and session handling. For indie hackers shipping fast, it's the "set and forget" solution that doesn't compromise on security.
Current pricing (verify in official docs): Free tier includes up to 10,000 monthly active users. Paid plans start at $25/month. Verify exact tiers at [Clerk pricing](https://clerk.com/pricing).
Prerequisites
Step 1: Create a Clerk Project (2 minutes)
1. Sign up at [clerk.com](https://clerk.com)
2. Click "Create Application"
3. Choose your stack: Next.js
4. Copy your keys:
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
- CLERK_SECRET_KEY
5. Note: Public key is safe to expose; secret key must stay private
Step 2: Install Dependencies (1 minute)
```bash npm install @clerk/nextjs ```
Verify installation: ```bash npm list @clerk/nextjs ```
You should see something like @clerk/nextjs@5.x.x (verify exact version in official [Clerk changelog](https://github.com/clerkinc/javascript/releases)).
Step 3: Configure Environment Variables (1 minute)
Create .env.local in your project root:
```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxx CLERK_SECRET_KEY=sk_test_xxxxxxxxxxxxx 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 ```
Important: Never commit .env.local to version control. Add it to .gitignore immediately.
Step 4: Wrap Your App with ClerkProvider (1 minute)
Update app/layout.tsx (or _app.tsx for Pages Router):
```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> ); } ```
Step 5: Create Auth Routes (2 minutes)
Clerk provides prebuilt UI components. Create these files:
Sign In Page
app/sign-in/[[...index]]/page.tsx:
```typescript import { SignIn } from '@clerk/nextjs';
export default function SignInPage() { return ( <div style={{ display: 'flex', justifyContent: 'center', marginTop: '50px' }}> <SignIn /> </div> ); } ```
Sign Up Page
app/sign-up/[[...index]]/page.tsx:
```typescript import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() { return ( <div style={{ display: 'flex', justifyContent: 'center', marginTop: '50px' }}> <SignUp /> </div> ); } ```
Step 6: Protect Routes (2 minutes)
Use auth() middleware to guard pages. Create app/middleware.ts:
```typescript import { auth } from '@clerk/nextjs/server'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) { const { userId } = await auth();
if (!userId && request.nextUrl.pathname === '/dashboard') { return NextResponse.redirect(new URL('/sign-in', request.url)); }
return NextResponse.next(); }
export const config = { matcher: ['/dashboard/:path*', '/api/protected/:path*'], }; ```
Production pattern: Always check userId exists before serving protected content.
Alternative: Server Components
For Next.js 13+, use the auth() function directly in server components:
```typescript import { auth } from '@clerk/nextjs/server';
export default async function DashboardPage() { const { userId } = await auth();
if (!userId) { redirect('/sign-in'); }
return <h1>Welcome back, {userId}</h1>; } ```
Real Errors You'll Hit
Error 1: Missing Environment Variables
``` Error: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is not set. Make sure to add it to your .env.local file. ```
Fix: Copy keys from Clerk dashboard. Restart dev server: npm run dev.
Error 2: Provider Not Wrapping App
``` Error: <ClerkProvider> must wrap your entire application. Please add it to your root layout. ```
Fix: Ensure ClerkProvider wraps {children} in app/layout.tsx.
Error 3: Async Auth in Client Component
``` Error: Cannot use 'await' in client component. Move 'auth()' to a server component or use useAuth() hook instead. ```
Fix: Use useAuth() hook for client components:
```typescript 'use client'; import { useAuth } from '@clerk/nextjs';
export function UserProfile() { const { userId, isLoaded } = useAuth();
if (!isLoaded) return <div>Loading...</div>; if (!userId) return <div>Not signed in</div>;
return <div>User ID: {userId}</div>; } ```
Verify It Works
1. Run dev server: npm run dev
2. Navigate to http://localhost:3000/sign-in
3. You should see Clerk's authentication UI
4. Sign up with email or social login (if configured)
5. After successful auth, you're redirected to /dashboard
Production Checklist
Next Steps
You've got auth. Now:
What am I missing?
Comments below! Did you hit errors we didn't cover? Upgrade from another auth provider? Use Clerk with a different stack (Remix, SvelteKit, Astro)? Let's improve this guide together.
For exact version numbers, always verify in [Clerk's official docs](https://clerk.com/docs).