clerk-prod-checklist

'Production readiness checklist for Clerk deployment.

5 Tools
clerk-pack Plugin
saas packs Category

Allowed Tools

ReadWriteEditGrepBash(npm:*)

Provided by Plugin

clerk-pack

Claude Code skill pack for Clerk authentication (24 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the clerk-pack plugin:

/plugin install clerk-pack@claude-code-plugins-plus

Click to copy

Instructions

Clerk Production Checklist

Overview

Complete checklist to ensure your Clerk integration is production-ready. Covers environment config, security hardening, monitoring, error handling, and compliance.

Prerequisites

  • Clerk integration working in development
  • Production environment and domain configured
  • CI/CD pipeline ready

Instructions

Step 1: Environment Configuration Checklist

Check Status Action
Using pklive keys [ ] Switch from test to live keys
CLERKSECRETKEY is sklive [ ] Never use test keys in production
.env.local in .gitignore [ ] Prevent accidental secret commits
CLERKWEBHOOKSECRET set [ ] Required for webhook verification
Production domain in Clerk Dashboard [ ] Dashboard > Domains
Sign-in/sign-up URLs configured [ ] Set NEXTPUBLICCLERKSIGNIN_URL etc.

Step 2: Validation Script


// scripts/prod-readiness.ts
import { createClerkClient } from '@clerk/backend'

async function validateProduction() {
  const checks: { name: string; pass: boolean; detail: string }[] = []

  // 1. Live keys check
  const pk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY || ''
  const sk = process.env.CLERK_SECRET_KEY || ''
  checks.push({
    name: 'Live publishable key',
    pass: pk.startsWith('pk_live_'),
    detail: pk.startsWith('pk_live_') ? 'Using live key' : `Using ${pk.slice(0, 8)}... (should be pk_live_)`,
  })
  checks.push({
    name: 'Live secret key',
    pass: sk.startsWith('sk_live_'),
    detail: sk.startsWith('sk_live_') ? 'Using live key' : 'Should be sk_live_ for production',
  })

  // 2. API connectivity
  try {
    const clerk = createClerkClient({ secretKey: sk })
    await clerk.users.getUserList({ limit: 1 })
    checks.push({ name: 'API connectivity', pass: true, detail: 'Backend API reachable' })
  } catch (err: any) {
    checks.push({ name: 'API connectivity', pass: false, detail: err.message })
  }

  // 3. Webhook secret
  checks.push({
    name: 'Webhook secret configured',
    pass: !!process.env.CLERK_WEBHOOK_SECRET,
    detail: process.env.CLERK_WEBHOOK_SECRET ? 'Set' : 'CLERK_WEBHOOK_SECRET missing',
  })

  // 4. Middleware exists
  const fs = await import('fs')
  const hasMiddleware = fs.existsSync('middleware.ts') || fs.existsSync('src/middleware.ts')
  checks.push({
    name: 'Middleware present',
    pass: hasMiddleware,
    detail: hasMiddleware ? 'Found' : 'middleware.ts not found at project root',
  })

  // Print results
  console.log('\n=== Clerk Production Readiness ===\n')
  for (const check of checks) {
    const icon = check.pass ? 'PASS' : 'FAIL'
    console.log(`[${icon}] ${check.name}: ${check.detail}`)
  }

  const allPass = checks.every((c) => c.pass)
  console.log(`\nResult: ${allPass ? 'READY for production' : 'NOT READY — fix failing checks'}`)
  process.exit(allPass ? 0 : 1)
}

validateProduction()

Run with:


npx tsx scripts/prod-readiness.ts

Step 3: Security Checklist

Check Status Action
Middleware protects all routes [ ] Verify non-public routes require auth
API routes check userId [ ] Return 401 if userId is null
Webhook signatures verified [ ] Use svix library for verification
CORS configured correctly [ ] Only allow production domain
Rate limiting on sensitive endpoints [ ] Use @upstash/ratelimit or similar
CSP headers set [ ] Add Clerk domains to Content-Security-Policy
No secret keys in client code [ ] CLERKSECRETKEY never exposed

Step 4: Monitoring Checklist

Check Status Action
Health check endpoint [ ] /api/health monitoring Clerk API
Error tracking (Sentry) [ ] Clerk user context in error reports
Auth event logging [ ] Log sign-in, sign-out, permission denied
Webhook monitoring [ ] Alert on failed webhook deliveries
Uptime monitoring [ ] External monitor hitting health endpoint

Step 5: Error Handling Checklist

Check Status Action
Custom error pages [ ] /not-found, /error pages handle auth errors
Graceful auth failures [ ] Redirect to sign-in, don't show stack traces
Webhook retry handling [ ] Idempotency keys prevent duplicate processing
Session expiry UX [ ] Show "session expired" prompt, not blank page

// app/error.tsx — global error boundary with auth context
'use client'
import { useAuth } from '@clerk/nextjs'

export default function Error({ error, reset }: { error: Error; reset: () => void }) {
  const { isSignedIn } = useAuth()

  return (
    <div>
      <h2>Something went wrong</h2>
      <p>{error.message}</p>
      <button onClick={reset}>Try again</button>
      {!isSignedIn && <a href="/sign-in">Sign in</a>}
    </div>
  )
}

Step 6: Performance Checklist

Check Status Action
Middleware matcher excludes static files [ ] Don't auth-check images, fonts, CSS
User data cached (React.cache()) [ ] Deduplicate within request
Auth components lazy loaded [ ] dynamic() for UserButton, SignInButton
Edge Runtime for middleware [ ] Faster cold starts on Vercel

Output

  • Environment configuration verified (live keys, webhook secret, domain)
  • Automated validation script (run in CI or before deploy)
  • Security, monitoring, error handling, and performance checklists
  • Global error boundary component with auth context

Error Handling

Error Cause Solution
Validation script fails Test keys in production Switch to pklive / sklive keys
API connectivity check fails Wrong secret key Verify key in Clerk Dashboard > API Keys
Middleware not found File in wrong location Place middleware.ts at project root (not inside app/)
Health check returns 503 Clerk API unreachable Check network, verify key, check status.clerk.com

Examples

CI Production Gate


# .github/workflows/deploy.yml — add as pre-deploy step
- name: Clerk production readiness
  run: npx tsx scripts/prod-readiness.ts
  env:
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.CLERK_PK_PROD }}
    CLERK_SECRET_KEY: ${{ secrets.CLERK_SK_PROD }}
    CLERK_WEBHOOK_SECRET: ${{ secrets.CLERK_WEBHOOK_SECRET_PROD }}

Resources

Next Steps

Proceed to clerk-upgrade-migration for SDK version upgrades.

Ready to use clerk-pack?