dev_tools
Back to guides

Next.js + Clerk Authentication

Add complete authentication with user management, social logins, and protected routes using Clerk.

Next.js
Clerk
Authentication
TypeScript
1

Create Next.js Project

Bootstrap a new Next.js app with TypeScript and the App Router.

npx create-next-app@latest my-app --typescript --tailwind --app --src-dir
2

Install Clerk SDK

Install the official Clerk Next.js SDK.

npm install @clerk/nextjs
3

Get Clerk API Keys

Create a new application at dashboard.clerk.com. Copy the NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY from the API Keys section.

.env.local
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
CLERK_SECRET_KEY=your_clerk_secret_key

# Optional: custom redirect paths
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
4

Wrap App with ClerkProvider

Add ClerkProvider to your root layout. This makes auth state available throughout your app. See ClerkProvider docs.

src/app/layout.tsx
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>
  )
}
5

Add Auth Middleware

Create src/middleware.ts to protect routes. The clerkMiddleware helper integrates with Next.js middleware to redirect unauthenticated users. See auth middleware docs.

src/middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isPublicRoute = createRouteMatcher([
  '/',
  '/sign-in(.*)',
  '/sign-up(.*)',
  '/api/webhooks(.*)',
])

export default clerkMiddleware(async (auth, req) => {
  if (!isPublicRoute(req)) {
    await auth.protect()
  }
})

export const config = {
  matcher: [
    '/((?!_next|[^?]*\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    '/(api|trpc)(.*)',
  ],
}
6

Create Sign-In and Sign-Up Pages

Add Clerk's pre-built auth UI components. Place them in the correct directories so Clerk's redirect variables work automatically.

src/app/sign-in/[[...sign-in]]/page.tsx
import { SignIn } from '@clerk/nextjs'

export default function SignInPage() {
  return (
    <main className="flex min-h-screen items-center justify-center">
      <SignIn />
    </main>
  )
}
💡Create an identical file at src/app/sign-up/[[...sign-up]]/page.tsx replacing <SignIn /> with <SignUp />
7

Build a Protected Dashboard

Use currentUser() on the server or useUser() on the client to access user data. Both are provided by the Clerk SDK.

src/app/dashboard/page.tsx
import { currentUser } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function DashboardPage() {
  const user = await currentUser()

  if (!user) redirect('/sign-in')

  return (
    <main className="p-8">
      <h1 className="text-2xl font-bold">
        Welcome back, {user.firstName}!
      </h1>
      <p className="text-muted-foreground mt-1">
        {user.primaryEmailAddress?.emailAddress}
      </p>
    </main>
  )
}
8

Add Navigation with Auth State

Use Clerk's <SignedIn>, <SignedOut>, and <UserButton> components to build a header that adapts to auth state.

src/components/Navbar.tsx
import {
  SignedIn,
  SignedOut,
  SignInButton,
  SignUpButton,
  UserButton,
} from '@clerk/nextjs'
import Link from 'next/link'

export function Navbar() {
  return (
    <header className="flex h-16 items-center justify-between border-b px-6">
      <Link href="/" className="font-semibold text-lg">My App</Link>
      <nav className="flex items-center gap-4">
        <SignedOut>
          <SignInButton mode="modal">
            <button className="text-sm font-medium">Sign in</button>
          </SignInButton>
          <SignUpButton mode="modal">
            <button className="rounded-md bg-black px-4 py-2 text-sm font-medium text-white">
              Get started
            </button>
          </SignUpButton>
        </SignedOut>
        <SignedIn>
          <Link href="/dashboard" className="text-sm">Dashboard</Link>
          <UserButton afterSignOutUrl="/" />
        </SignedIn>
      </nav>
    </header>
  )
}
9

Protect API Routes

Use auth() in Route Handlers to secure API endpoints. Returns userId: null for unauthenticated requests.

src/app/api/protected/route.ts
import { auth } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'

export async function GET() {
  const { userId } = await auth()

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }

  return NextResponse.json({
    message: 'This is protected data',
    userId,
  })
}
10

Start Development Server

Run the dev server and navigate to / to see the public page, then try /dashboard to trigger the auth redirect.

npm run dev
💡Visit http://localhost:3000 — unauthenticated users hitting /dashboard will be redirected to /sign-in automatically.

Found this guide helpful? Check out more tools and guides.

Browse All Guides