Clerk Auth Setup in Under 10 Minutes - 2026 Guide
Production-ready Clerk authentication setup with Next.js. Real error solutions, exact versions, and copy-paste code patterns.
TL;DR
Clerk handles auth complexity. Install SDK, add environment variables, wrap your app with <ClerkProvider>, protect routes with middleware. Done in ~10 minutes. Real errors and solutions included below.
---
Why Clerk for 2026?
Auth is a tax on shipping. Clerk lets you skip building login UIs, managing sessions, and handling OAuth plumbing. The alternative—rolling your own—costs 40+ hours and introduces security holes.
This guide covers the minimal viable setup. Verify current pricing and features in [official Clerk docs](https://clerk.com/docs).
---
Step 1: Create a Clerk Project (2 minutes)
1. Go to [clerk.com](https://clerk.com) and sign up 2. Create a new application 3. Choose "Next.js" as your framework (if using Next.js) 4. Copy your Frontend API Key and Secret Key
You'll see a dashboard with your keys. Save them.
---
Step 2: Install Clerk SDK (1 minute)
For Next.js (verify latest in [Clerk SDK docs](https://clerk.com/docs/references/nextjs/overview)):
```bash npm install @clerk/nextjs ```
Current stable versions (verify in official docs):
@clerk/nextjs: 5.x (check package.json after install)@clerk/react: 5.x@clerk/clerk-js: 5.x---
Step 3: Set Environment Variables (1 minute)
Create .env.local:
```env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your_key_here CLERK_SECRET_KEY=sk_test_your_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 ```
Replace with your actual keys from step 1. The NEXT_PUBLIC_ prefix means these are safe to expose to the browser (they're public keys). The secret key stays server-only.
---
Step 4: Wrap Your App with ClerkProvider (2 minutes)
app/layout.tsx (App 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> ); } ```
pages/_app.tsx (Pages Router - legacy):
```typescript import { ClerkProvider } from '@clerk/nextjs'; import type { AppProps } from 'next/app';
function MyApp({ Component, pageProps }: AppProps) { return ( <ClerkProvider> <Component {...pageProps} /> </ClerkProvider> ); }
export default MyApp; ```
---
Step 5: Create Sign-In & Sign-Up Pages (3 minutes)
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> ); } ```
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> ); } ```
The [[...index]] pattern tells Next.js to catch all sign-in routes under /sign-in.
---
Step 6: Protect Routes with Middleware (2 minutes)
Create middleware.ts at your project root (same level as app/ or pages/):
```typescript import { authMiddleware } from '@clerk/nextjs';
export default authMiddleware({ publicRoutes: ['/', '/api/webhooks/clerk'], });
export const config = { matcher: ['/((?!.*\\..*|\\_next).*)', '/', '/(api|trpc)(.*)', '/(.*)/edit'], }; ```
This blocks access to routes unless the user is signed in, except for public routes you specify.
---
Real Console Errors & Fixes
Error 1: Missing Environment Variables
``` Error: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY is not set. Make sure to set it in your environment variables. ```
Fix: You didn't paste your keys into .env.local. Restart your dev server after adding them:
```bash rm .next npm run dev ```
Error 2: Invalid Clerk Token
``` ClerkRuntimeError: The Clerk secret key is invalid. Verify NEXT_PUBLIC_CLERK_SECRET_KEY is set correctly. ```
Fix: You used your publishable key instead of your secret key in CLERK_SECRET_KEY. Swap them and restart.
Error 3: Middleware Not Protecting Routes
``` Error: User accessed /dashboard without authentication (but no error appeared—page loaded anyway) ```
Fix: Middleware file needs to be named exactly middleware.ts at your project root, not in app/. If it's in the wrong location, Clerk can't intercept requests.
---
Protected Page Example
app/dashboard/page.tsx:
```typescript import { auth } from '@clerk/nextjs'; import { redirect } from 'next/navigation';
export default async function DashboardPage() { const { userId } = auth();
if (!userId) { redirect('/sign-in'); }
return ( <div> <h1>Dashboard</h1> <p>User ID: {userId}</p> </div> ); } ```
The auth() function gives you the current user's ID server-side. Use it to gate content or query databases.
---
Client-Side Usage
Get user info in components:
```typescript 'use client';
import { useAuth, useUser } from '@clerk/nextjs';
export function UserProfile() { const { userId } = useAuth(); const { user } = useUser();
return ( <div> <p>ID: {userId}</p> <p>Email: {user?.emailAddresses[0]?.emailAddress}</p> </div> ); } ```
Mark components with 'use client' to access hooks.
---
Production Checklist
---
What am I missing?
This covers the happy path. What would *you* add?
The Clerk docs evolve—if something here contradicts official Clerk docs, that's a gap. Flag it.
---