Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
gocallum avatar

Clerk Nextjs Skills

  • 377 installs
  • 22 repo stars
  • Updated January 21, 2026
  • gocallum/nextjs16-agent-skills

clerk-nextjs-skills is a Claude Code agent skill that integrates Clerk authentication into Next.js 16 App Router apps for developers who need protected routes, sessions, webhooks, and multi-tenant sign-in.

About

clerk-nextjs-skills is a Claude Code agent skill from gocallum/nextjs16-agent-skills that walks developers through Clerk authentication for Next.js 16 App Router projects. The skill documents proxy.ts with clerkMiddleware() as the Next.js 16 replacement for middleware.ts, required .env.local keys, ClerkProvider in app/layout.tsx, and route matchers for pages, API routes, and tRPC endpoints. It covers server components, client components, and server actions for session access, webhook setup, OAuth token verification, and MCP server security with @clerk/mcp-tools. Migration guidance explains the filename change from middleware.ts to proxy.ts with no functional differences. Examples use pnpm to install @clerk/nextjs and configure public, protected, and conditional routes. Developers reach for clerk-nextjs-skills when building multi-tenant SaaS sign-in, migrating Clerk apps to Next.js 16, or securing MCP-enabled AI workflows on Vercel.

  • Clerk + Next.js 16
  • Middleware protection
  • Server and client sessions
  • Webhooks and orgs
  • SaaS sign-in flows

Clerk Nextjs Skills by the numbers

  • 377 all-time installs (skills.sh)
  • Ranked #1,110 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Jul 24, 2026 (Skillselion catalog sync)
npx skills add https://github.com/gocallum/nextjs16-agent-skills --skill clerk-nextjs-skills

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs377
repo stars22
Last updatedJanuary 21, 2026
Repositorygocallum/nextjs16-agent-skills

How do you integrate Clerk auth in Next.js 16?

Integrate Clerk authentication into Next.js 16 apps—middleware, protected routes, server actions, webhooks, and session handling for multi-tenant SaaS sign-in flows.

Who is it for?

Next.js 16 developers implementing Clerk sign-in, session handling, and route protection in App Router SaaS apps.

Skip if: Developers on Next.js 15 middleware.ts-only stacks or projects using Auth.js instead of Clerk.

When should I use this skill?

User asks to add Clerk auth, migrate middleware.ts to proxy.ts, or secure Next.js 16 routes and MCP servers

What you get

Working proxy.ts middleware, ClerkProvider layout, env config, protected routes, webhooks, and MCP OAuth setup

  • proxy.ts middleware
  • ClerkProvider layout
  • protected route matchers

By the numbers

  • Covers Next.js 16+ proxy.ts convention replacing Next.js 15 middleware.ts
  • Documents MCP server OAuth integration alongside standard Clerk App Router setup

Files

SKILL.mdMarkdownGitHub ↗

Links

Quick Start

1. Install Dependencies (Using pnpm)

pnpm add @clerk/nextjs
# For MCP server integration, also install:
pnpm add @vercel/mcp-adapter @clerk/mcp-tools

2. Create proxy.ts (Next.js 16)

The proxy.ts file replaces middleware.ts from Next.js 15. Create it at the root or in /src:

// proxy.ts (or src/proxy.ts)
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware()

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)(.*)',
  ],
}

3. Set Environment Variables

Create .env.local in your project root:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key_here
CLERK_SECRET_KEY=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=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

4. Add ClerkProvider to Layout

// app/layout.tsx
import {
  ClerkProvider,
  SignInButton,
  SignUpButton,
  SignedIn,
  SignedOut,
  UserButton,
} 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>
          <header className="flex justify-end items-center p-4 gap-4 h-16">
            <SignedOut>
              <SignInButton />
              <SignUpButton />
            </SignedOut>
            <SignedIn>
              <UserButton />
            </SignedIn>
          </header>
          {children}
        </body>
      </html>
    </ClerkProvider>
  )
}

5. Run Your App

pnpm dev

Visit http://localhost:3000 and click "Sign Up" to create your first user.

Key Concepts

proxy.ts vs middleware.ts

  • Next.js 16 (App Router): Use proxy.ts for Clerk middleware
  • Next.js ≤15: Use middleware.ts with identical code (filename only differs)
  • Clerk's clerkMiddleware() function is the same regardless of filename
  • The matcher configuration ensures proper route handling and performance

Protecting Routes

By default, clerkMiddleware() does not protect routes—all are public. Use auth.protect() to require authentication:

// Protect specific route
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  const { userId } = await auth()
  
  if (!userId) {
    // Redirect handled by clerkMiddleware
  }
  
  return <div>Protected content for {userId}</div>
}

Or protect all routes in proxy.ts:

import { clerkMiddleware } from '@clerk/nextjs/server'

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

Environment Variable Validation

Check for required Clerk keys before runtime:

// lib/clerk-config.ts
export function validateClerkEnv() {
  const required = [
    'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
    'CLERK_SECRET_KEY',
  ]
  
  const missing = required.filter(key => !process.env[key])
  
  if (missing.length > 0) {
    throw new Error(`Missing required Clerk environment variables: ${missing.join(', ')}`)
  }
}

Accessing User Data

Use Clerk hooks in client components:

// app/components/user-profile.tsx
'use client'

import { useUser } from '@clerk/nextjs'

export function UserProfile() {
  const { user, isLoaded } = useUser()
  
  if (!isLoaded) return <div>Loading...</div>
  
  if (!user) return <div>Not signed in</div>
  
  return (
    <div>
      <h1>{user.fullName}</h1>
      <p>{user.primaryEmailAddress?.emailAddress}</p>
    </div>
  )
}

Or in server components/actions:

// app/actions.ts
'use server'

import { auth, clerkClient } from '@clerk/nextjs/server'

export async function getUserData() {
  const { userId } = await auth()
  
  if (!userId) {
    throw new Error('Unauthorized')
  }
  
  const clerk = await clerkClient()
  const user = await clerk.users.getUser(userId)
  
  return user
}

Migrating from middleware.ts (Next.js 15) to proxy.ts (Next.js 16)

Step-by-Step Migration

1. Rename the file from middleware.ts to proxy.ts (location remains same: root or /src)

2. Keep the code identical - No functional changes needed:

   // Before (middleware.ts)
   import { clerkMiddleware } from '@clerk/nextjs/server'
   export default clerkMiddleware()
   export const config = { ... }
   
   // After (proxy.ts) - Same code
   import { clerkMiddleware } from '@clerk/nextjs/server'
   export default clerkMiddleware()
   export const config = { ... }

3. Update Next.js version:

   pnpm add next@latest

4. Verify environment variables are still in .env.local (no changes needed)

5. Test the migration:

   pnpm dev

Troubleshooting Migration

  • If routes aren't protected, ensure proxy.ts is in the correct location (root or /src)
  • Check that .env.local has all required Clerk keys
  • Clear .next cache if middleware changes don't take effect: rm -rf .next && pnpm dev
  • Verify Next.js version is 16.0+: pnpm list next

Building an MCP Server with Clerk

See CLERK_MCP_SERVER_SETUP.md for complete MCP server integration.

Quick MCP Setup Summary

1. Install MCP dependencies:

   pnpm add @vercel/mcp-adapter @clerk/mcp-tools

2. Create MCP route at app/[transport]/route.ts:

   import { verifyClerkToken } from '@clerk/mcp-tools/next'
   import { createMcpHandler, withMcpAuth } from '@vercel/mcp-adapter'
   import { auth, clerkClient } from '@clerk/nextjs/server'
   
   const clerk = await clerkClient()
   
   const handler = createMcpHandler((server) => {
     server.tool(
       'get-clerk-user-data',
       'Gets data about the Clerk user that authorized this request',
       {},
       async (_, { authInfo }) => {
         const userId = authInfo!.extra!.userId! as string
         const userData = await clerk.users.getUser(userId)
         return {
           content: [{ type: 'text', text: JSON.stringify(userData) }],
         }
       },
     )
   })
   
   const authHandler = withMcpAuth(
     handler,
     async (_, token) => {
       const clerkAuth = await auth({ acceptsToken: 'oauth_token' })
       return verifyClerkToken(clerkAuth, token)
     },
     {
       required: true,
       resourceMetadataPath: '/.well-known/oauth-protected-resource/mcp',
     },
   )
   
   export { authHandler as GET, authHandler as POST }

3. Expose OAuth metadata endpoints (see references for complete setup)

4. Update proxy.ts to exclude .well-known endpoints:

   import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
   
   const isPublicRoute = createRouteMatcher([
     '/.well-known/oauth-authorization-server(.*)',
     '/.well-known/oauth-protected-resource(.*)',
   ])
   
   export default clerkMiddleware(async (auth, req) => {
     if (isPublicRoute(req)) return
     await auth.protect()
   })

5. Enable Dynamic Client Registration in Clerk Dashboard

Best Practices

1. Environment Variable Management

  • Always use .env.local for development (never commit sensitive keys)
  • Validate environment variables on application startup
  • Use NEXT_PUBLIC_ prefix ONLY for non-sensitive keys that are safe to expose
  • For production, set environment variables in your deployment platform (Vercel, etc.)

2. Route Protection Strategies

// Option A: Protect all routes
export default clerkMiddleware(async (auth, req) => {
  await auth.protect()
})

// Option B: Protect specific routes
import { createRouteMatcher } from '@clerk/nextjs/server'

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/api/user(.*)'])

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

// Option C: Public routes with opt-in protection
const isPublicRoute = createRouteMatcher(['/sign-in(.*)', '/sign-up(.*)'])

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

3. MCP Server Security

  • Enable Dynamic Client Registration in Clerk Dashboard
  • Keep .well-known endpoints public but protect all MCP tools with OAuth
  • Use acceptsToken: 'oauth_token' in auth() to require machine tokens
  • OAuth tokens are free during public beta (pricing TBD)
  • Always verify tokens with verifyClerkToken() before exposing user data

4. Performance & Caching

  • Use clerkClient() for server-side user queries (cached automatically)
  • Leverage React Server Components for secure user data access
  • Cache user data when possible to reduce API calls
  • Use @clerk/nextjs hooks only in Client Components ('use client')

5. Production Deployment

  • Set all environment variables in your deployment platform
  • Use Clerk's production instance keys (not development keys)
  • Test authentication flow in staging environment before production
  • Monitor Clerk Dashboard for authentication errors
  • Keep @clerk/nextjs updated: pnpm update @clerk/nextjs

Troubleshooting

Issues & Solutions

IssueSolution
"Missing environment variables"Ensure .env.local has NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY
Middleware not protecting routesVerify proxy.ts is in root or /src directory, not in app/
Sign-in/sign-up pages not workingCheck NEXT_PUBLIC_CLERK_SIGN_IN_URL and NEXT_PUBLIC_CLERK_SIGN_UP_URL in .env.local
User data returns nullEnsure user is authenticated: check userId is not null before calling getUser()
MCP server OAuth failsEnable Dynamic Client Registration in Clerk Dashboard OAuth Applications
Changes not taking effectClear .next cache: rm -rf .next and restart pnpm dev
"proxy.ts" not recognizedVerify Next.js version is 16.0+: pnpm list next

Common Next.js 16 Gotchas

  • File naming: Must be proxy.ts (not middleware.ts) for Next.js 16
  • Location: Place proxy.ts at project root or in /src directory, NOT in app/
  • Re-exports: Config object must be exported from proxy.ts for matcher to work
  • Async operations: clerkMiddleware() is async-ready; use await auth.protect() for route protection

Debug Mode

Enable debug logging:

// proxy.ts
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware((auth, req) => {
  if (process.env.DEBUG_CLERK) {
    console.log('Request URL:', req.nextUrl.pathname)
    console.log('User ID:', auth.sessionClaims?.sub)
  }
})

Run with debug:

DEBUG_CLERK=1 pnpm dev

Related Skills

  • [mcp-server-skills](../mcp-server-skills/SKILL.md): General MCP server patterns with Vercel adapter
  • [nextjs16-skills](../nextjs16-skills/SKILL.MD): Next.js 16 features, breaking changes, and best practices
  • [authjs-skills](../authjs-skills/SKILL.md): Alternative authentication using Auth.js (Auth0, GitHub, etc.)

Resources

Related skills

How it compares

Pick clerk-nextjs-skills over generic Next.js auth guides when you need Clerk-specific proxy.ts migration and MCP OAuth patterns for Next.js 16.

FAQ

Does clerk-nextjs-skills support Next.js 15?

clerk-nextjs-skills targets Next.js 16+ App Router with proxy.ts. Next.js 15.x uses middleware.ts instead; the skill includes a migration guide explaining the filename change with identical clerkMiddleware() code.

What files does Clerk setup require in Next.js 16?

clerk-nextjs-skills requires proxy.ts at the project root or src/, Clerk keys in .env.local, ClerkProvider in app/layout.tsx, and pnpm add @clerk/nextjs. Route matchers define public versus protected pages and API endpoints.

Backend & APIsfrontendbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.