Clerk Auth Setup in Under 10 Minutes – 2026 Guide
Step-by-step Clerk authentication setup for React/Next.js. Real error fixes, production patterns, and exact CLI commands to get auth working fast.
TL;DR
Clerk handles authentication complexity so you don't have to. This guide walks through a production-ready setup: create a Clerk app, install SDK (verify latest version in official docs), add environment variables, wrap your app with <ClerkProvider>, and deploy protected routes in ~10 minutes.
---
Why Clerk for Authentication?
Managing auth yourself means handling password hashing, session tokens, OAuth flows, and TOTP. Clerk abstracts this away with a clean developer experience and SDKs that "just work."
What you get:
---
Step 1: Create a Clerk Application (2 minutes)
1. Go to [clerk.com](https://clerk.com) and click "Create account" 2. Verify your email 3. Name your application (e.g., "my-indie-app") 4. Choose your tech stack (we'll use Next.js as the example) 5. Copy your Frontend API Key and Backend API Key — you'll need these immediately
Verify in official docs: API key format and permissions change between Clerk versions. Check [https://clerk.com/docs/reference/backend-api](https://clerk.com/docs/reference/backend-api) for current key structure.
---
Step 2: Install Clerk SDK (2 minutes)
For Next.js (App Router):
```bash npm install @clerk/nextjs ```
For React (Vite/CRA):
```bash npm install @clerk/react ```
Verify in official docs: SDK versions update frequently. Before installing, check [https://clerk.com/docs/quickstarts](https://clerk.com/docs/quickstarts) for the latest version and any breaking changes.
At time of writing, @clerk/nextjs@5.x and @clerk/react@5.x are current. Always run npm info @clerk/nextjs to confirm the latest major version.
---
Step 3: Configure Environment Variables (1 minute)
Create a .env.local file in your project root:
```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_XXXXXXXXXXXXXXXXXXXXX CLERK_SECRET_KEY=sk_live_XXXXXXXXXXXXXXXXXXXXX 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 ```
Important: Only the NEXT_PUBLIC_* keys are safe for client-side exposure. Never commit CLERK_SECRET_KEY to version control.
---
Step 4: Wrap Your App with ClerkProvider (2 minutes)
For Next.js App Router (app/layout.tsx):
```typescript import { ClerkProvider } from '@clerk/nextjs'; import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) { return ( <ClerkProvider> <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ); } ```
For React (Vite) (src/main.tsx):
```typescript import React from 'react'; import ReactDOM from 'react-dom/client'; import { ClerkProvider } from '@clerk/react'; import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <ClerkProvider publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}> <App /> </ClerkProvider> </React.StrictMode> ); ```
---
Step 5: Add Sign-In and Sign-Up Pages (3 minutes)
For Next.js, create 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> ); } ```
Create app/sign-up/[[...index]]/page.tsx with the same pattern but import SignUp.
For React, create a route component:
```typescript import { SignIn } from '@clerk/react';
export function SignInPage() { return ( <div className="flex items-center justify-center min-h-screen"> <SignIn routing="path" path="/sign-in" /> </div> ); } ```
---
Step 6: Protect Routes (2 minutes)
Next.js with Middleware (middleware.ts at project root):
```typescript import { authMiddleware } from '@clerk/nextjs';
export default authMiddleware({ publicRoutes: ['/'], ignoredRoutes: ['/api/public'], });
export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'] }; ```
Server-side protection (app/dashboard/page.tsx):
```typescript import { auth, redirect } from '@clerk/nextjs';
export default async function DashboardPage() { const { userId } = await auth(); if (!userId) { redirect('/sign-in'); } return <div>Welcome, {userId}</div>; } ```
---
Real Error Messages You'll Hit
Error 1: Missing Environment Variable
``` Error: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is not provided at ClerkProvider (clerk-provider.tsx:42) ```Fix: Ensure your .env.local has the key AND you've restarted your dev server after adding it.
Error 2: Invalid Publishable Key Format
``` Warning: Clerk: The Publishable Key is not a valid Clerk Publishable Key. Make sure your environment variables are set correctly. ```Fix: Your key should start with pk_live_ or pk_test_. Verify you copied it correctly from the Clerk dashboard (not the Secret Key).
Error 3: Redirect Loop on Protected Routes
``` Error: Maximum call stack size exceeded at authMiddleware ```Fix: Ensure your publicRoutes array includes /sign-in and /sign-up, or you'll loop infinitely redirecting unauthenticated users.
---
Production Checklist
---
What am I missing?
This guide covers the happy path. What didn't work for you? Drop a comment about:
I'll update this guide based on real feedback.