| name | clerk-performance-tuning |
| description | Optimize Clerk authentication performance.
Use when improving auth response times, reducing latency,
or optimizing Clerk SDK usage.
Trigger with phrases like "clerk performance", "clerk optimization",
"clerk slow", "clerk latency", "optimize clerk".
|
| allowed-tools | Read, Write, Edit, Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Clerk Performance Tuning
Overview
Optimize Clerk authentication for best performance and user experience.
Prerequisites
- Clerk integration working
- Performance monitoring in place
- Understanding of application architecture
Instructions
Step 1: Optimize Middleware
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
const isPublicRoute = createRouteMatcher([
'/',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/public(.*)',
'/api/webhooks(.*)'
])
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)(.*)'
]
}
export default clerkMiddleware(async (auth, request) => {
if (isPublicRoute(request)) {
return
}
await auth.protect()
})
Step 2: Implement User Data Caching
import { unstable_cache } from 'next/cache'
import { clerkClient, currentUser } from '@clerk/nextjs/server'
export const getCachedUser = unstable_cache(
async (userId: string) => {
const client = await clerkClient()
return client.users.getUser(userId)
},
['user-data'],
{
revalidate: 60,
tags: ['users']
}
)
const userCache = new Map<string, { data: any; expiry: number }>()
export async function getUserFast(userId: string) {
const cached = userCache.get(userId)
const now = Date.now()
if (cached && cached.expiry > now) {
return cached.data
}
user = (userId)
userCache.(userId, {
: user,
: now +
})
user
}
() {
userCache.(userId)
}
Step 3: Optimize Token Handling
'use client'
import { useAuth } from '@clerk/nextjs'
import { useRef } from 'react'
export function useOptimizedAuth() {
const { getToken, userId, isLoaded } = useAuth()
const tokenCache = useRef<{
token: string | null
expiry: number
} | null>(null)
const getCachedToken = async () => {
const now = Date.now()
if (tokenCache.current &&
tokenCache.current.token &&
tokenCache.current.expiry > now + 300000) {
return tokenCache.current.token
}
const token = await getToken()
if (token) {
const payload = JSON.((token.()[]))
tokenCache. = {
token,
: payload. *
}
}
token
}
{ getCachedToken, userId, isLoaded }
}
() {
{ getCachedToken } = ()
(: , : = {}) => {
token = ()
(url, {
...options,
: {
...options.,
: ,
:
}
})
}
}
Step 4: Lazy Load Auth Components
'use client'
import dynamic from 'next/dynamic'
import { Suspense } from 'react'
const UserButton = dynamic(
() => import('@clerk/nextjs').then(mod => mod.UserButton),
{
loading: () => <div className="w-8 h-8 bg-gray-200 rounded-full animate-pulse" />,
ssr: false
}
)
const SignInButton = dynamic(
() => import('@clerk/nextjs').then(mod => mod.SignInButton),
{
loading: () => <button className="btn" disabled>Sign In</button>,
ssr: false
}
)
export function LazyUserButton() {
(
)
}
Step 5: Optimize Server Components
import { auth } from '@clerk/nextjs/server'
import { Suspense } from 'react'
export default async function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
{/* Stream user-specific content */}
<Suspense fallback={<UserDataSkeleton />}>
<UserData />
</Suspense>
{/* Non-auth content renders immediately */}
<StaticContent />
</div>
)
}
async function UserData() {
const { userId } = await auth()
const [user, stats, notifications] = await Promise.all([
getUser(userId!),
getUserStats(userId!),
getNotifications(userId!)
])
return (
)
}
Step 6: Edge Runtime Optimization
import { auth } from '@clerk/nextjs/server'
export const runtime = 'edge'
export async function GET() {
const { userId } = await auth()
if (!userId) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
return Response.json({ userId })
}
Performance Metrics
| Operation | Target | Optimization |
|---|
| Middleware check | < 10ms | Route matcher pre-compilation |
| Token validation | < 50ms | JWT caching |
| User fetch | < 100ms | Multi-level caching |
| Page load (auth) | < 200ms | Streaming + lazy load |
Monitoring
export function measureAuthPerformance<T>(
name: string,
operation: () => Promise<T>
): Promise<T> {
const start = performance.now()
return operation().finally(() => {
const duration = performance.now() - start
console.log(`[Clerk Perf] ${name}: ${duration.toFixed(2)}ms`)
if (duration > 100) {
console.warn(`[Clerk Perf] Slow operation: ${name}`)
}
})
}
const user = await measureAuthPerformance('getUser', () =>
clerkClient.users.getUser(userId)
)
Output
- Optimized middleware configuration
- Multi-level caching strategy
- Token management optimization
- Lazy loading for auth components
Error Handling
| Issue | Cause | Solution |
|---|
| Slow page loads | Blocking auth calls | Use Suspense boundaries |
| High latency | No caching | Implement token/user cache |
| Bundle size | All components loaded | Lazy load auth components |
| Cold starts | Node runtime | Use Edge runtime |
Resources
Next Steps
Proceed to clerk-cost-tuning for cost optimization strategies.