Clerk Auth Setup in Under 10 Minutes - 2026 Guide
Step-by-step Clerk authentication setup for Next.js. Real errors, production code patterns, and exact version numbers.
TL;DR
Clerk handles authentication in minutes: create an app, grab API keys, install SDK, wrap your app with <ClerkProvider>, and protect routes. No backend auth logic needed.
---
Why Clerk for Indie Hackers?
Authentication is the boring part nobody wants to build. Clerk removes that frictionβyou get user management, social login, passwordless auth, and session handling without writing a single login form.
For context, see our [JWT implementation guide](/?guide=jwt-auth) if you're considering alternatives.
Step 1: Create Your Clerk Application (2 minutes)
1. Sign up at [https://dashboard.clerk.com](https://dashboard.clerk.com) 2. Create a new application 3. Choose your frontend framework (Next.js, React, Vue, etc.) 4. You'll get two keys: - Publishable Key (safe for frontend) - Secret Key (never expose this)
Note: Verify current pricing and feature tiers in [official Clerk pricing](https://clerk.com/pricing) as these change quarterly.
Step 2: Install Dependencies (1 minute)
For Next.js 14+ with App Router:
```bash npm install @clerk/nextjs
or
yarn add @clerk/nextjs ```Verify you're installing @clerk/nextjs (not clerk directly) for proper Next.js integration.
Step 3: Environment Variables (1 minute)
Create .env.local:
```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your_publishable_key_here CLERK_SECRET_KEY=sk_test_your_secret_key_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=/onboarding ```
Critical: The NEXT_PUBLIC_ prefix is required for browser-accessible variables. Only Publishable Key should have it.
Step 4: Wrap Your App with ClerkProvider (2 minutes)
In app/layout.tsx (Next.js 13+ App Router):
```typescript import { ClerkProvider } from '@clerk/nextjs'; import type { Metadata } from 'next';
export const metadata: Metadata = { title: 'My App', description: 'Authenticated with Clerk', };
export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <ClerkProvider> <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ); } ```
Step 5: Create Auth Pages (2 minutes)
Clerk provides pre-built components. Create app/sign-in/[[...index]]/page.tsx:
```typescript import { SignIn } from '@clerk/nextjs';
export default function SignInPage() { return ( <div className="flex justify-center items-center min-h-screen"> <SignIn /> </div> ); } ```
Create app/sign-up/[[...index]]/page.tsx:
```typescript import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() { return ( <div className="flex justify-center items-center min-h-screen"> <SignUp /> </div> ); } ```
The [[...index]] route handles Clerk's internal routing.
Step 6: Protect Routes (2 minutes)
For a public homepage and protected dashboard:
Option A: Middleware (recommended)
Create middleware.ts at project root:
```typescript import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/settings(.*)', '/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)(.*)', ], }; ```
Option B: Route Handler (API protection)
```typescript // app/api/protected/route.ts import { auth } from '@clerk/nextjs/server';
export async function GET() { const { userId } = await auth();
if (!userId) { return Response.json({ error: 'Unauthorized' }, { status: 401 }); }
return Response.json({ message: 'Protected data', userId }); } ```
Common Console Errors You'll Hit
Error #1:
```
Error: Clerk: Missing NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
```
Fix: Verify .env.local exists, restart dev server (npm run dev), and check the key prefix is correct.
Error #2:
```
Error: clerkMiddleware must be used with ClerkProvider
```
Fix: Ensure ClerkProvider wraps your entire app in layout.tsx. Middleware won't work without it.
Error #3:
```
Error: Invalid sign in URL. The URL must be a relative URL
```
Fix: Check NEXT_PUBLIC_CLERK_SIGN_IN_URL in .env.local uses relative paths (/sign-in, not https://...).
Accessing User Data in Components
In any client component:
```typescript 'use client';
import { useUser, useAuth } from '@clerk/nextjs';
export default function UserProfile() { const { user, isLoaded } = useUser(); const { userId } = useAuth();
if (!isLoaded) return <div>Loading...</div>;
return ( <div> <h1>Welcome, {user?.firstName}!</h1> <p>Email: {user?.primaryEmailAddress?.emailAddress}</p> <p>User ID: {userId}</p> </div> ); } ```
Production Checklist
For deeper authentication patterns, see our [OAuth implementation guide](/?guide=oauth-setup).
Pricing & Rate Limits (verify in official docs)
Clerk's free tier includes 500 monthly active users. Verify current limits at [official docs](https://clerk.com/docs/deployments/overview) as pricing structure may change.
What am I missing?
This guide covers the happy path. What are you hitting that isn't covered? Missing:
Drop corrections, real errors you're seeing, or production gotchas in comments. This resource is only useful if it's accurate for *your* stack.