clerk-multi-env-setup
Manages configuration for Clerk across development, staging, and production environments with safe promotion workflows.
Install
mkdir -p .claude/skills/clerk-multi-env-setup && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5412" && unzip -o skill.zip -d .claude/skills/clerk-multi-env-setup && rm skill.zipInstalls to .claude/skills/clerk-multi-env-setup
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Configure Clerk for multiple environments (dev, staging, production).Key capabilities
- →Create environment-specific Clerk instances
- →Configure environment-aware redirect origins
- →Validate environment variables at startup
- →Implement CI/CD environment promotion
- →Manage per-environment webhook secrets
How it works
It organizes Clerk instances by environment and uses startup validation to ensure publishable and secret keys originate from the same instance.
Inputs & outputs
When to use clerk-multi-env-setup
- →Create Clerk instances for dev and prod
- →Manage environment variables for Clerk
- →Implement multi-environment promotion
- →Configure staging authentication
About this skill
Clerk Multi-Environment Setup
Overview
Configure Clerk across development, staging, and production environments with separate instances, environment-aware configuration, and safe promotion workflows.
Prerequisites
- Clerk account (one instance per environment recommended)
- CI/CD pipeline (GitHub Actions, Vercel, etc.)
- Environment variable management in place
Instructions
Step 1: Create Clerk Instances
Create separate Clerk instances in the Dashboard for each environment:
| Environment | Instance | Key Prefix | Domain |
|---|---|---|---|
| Development | my-app-dev | pk_test_ / sk_test_ | localhost:3000 |
| Staging | my-app-staging | pk_test_ / sk_test_ | staging.myapp.com |
| Production | my-app-prod | pk_live_ / sk_live_ | myapp.com |
Step 2: Environment Configuration Files
# .env.local (development - git-ignored)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_dev...
CLERK_SECRET_KEY=sk_test_dev...
CLERK_WEBHOOK_SECRET=whsec_dev...
# .env.staging (staging)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_staging...
CLERK_SECRET_KEY=sk_test_staging...
CLERK_WEBHOOK_SECRET=whsec_staging...
# .env.production (production)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_prod...
CLERK_SECRET_KEY=sk_live_prod...
CLERK_WEBHOOK_SECRET=whsec_prod...
Step 3: Environment-Aware Configuration
// lib/clerk-config.ts
type ClerkEnv = 'development' | 'staging' | 'production'
function getClerkEnv(): ClerkEnv {
const key = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY || ''
if (key.startsWith('pk_live_')) return 'production'
if (process.env.VERCEL_ENV === 'preview') return 'staging'
return 'development'
}
export const clerkConfig = {
env: getClerkEnv(),
get isDev() { return this.env === 'development' },
get isProd() { return this.env === 'production' },
signInUrl: '/sign-in',
signUpUrl: '/sign-up',
afterSignInUrl: '/dashboard',
get allowedRedirectOrigins() {
switch (this.env) {
case 'production': return ['https://myapp.com']
case 'staging': return ['https://staging.myapp.com']
default: return ['http://localhost:3000']
}
},
}
Step 4: Startup Validation
// lib/validate-env.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 Clerk env vars: ${missing.join(', ')}`)
}
const pk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!
const sk = process.env.CLERK_SECRET_KEY!
// Prevent key mismatch (test keys with live keys)
const pkIsLive = pk.startsWith('pk_live_')
const skIsLive = sk.startsWith('sk_live_')
if (pkIsLive !== skIsLive) {
throw new Error('Clerk key mismatch: publishable and secret keys must be from same environment')
}
// Warn if using live keys in development
if (pkIsLive && process.env.NODE_ENV === 'development') {
console.warn('WARNING: Using production Clerk keys in development mode')
}
}
Call at app startup:
// app/layout.tsx
import { validateClerkEnv } from '@/lib/validate-env'
validateClerkEnv()
Step 5: Webhook Configuration Per Environment
// app/api/webhooks/clerk/route.ts
import { headers } from 'next/headers'
import { Webhook } from 'svix'
export async function POST(req: Request) {
// Each environment uses its own webhook secret
const secret = process.env.CLERK_WEBHOOK_SECRET
if (!secret) {
console.error('CLERK_WEBHOOK_SECRET not configured for this environment')
return new Response('Server error', { status: 500 })
}
// Verification logic (same across environments)
const headerPayload = await headers()
const wh = new Webhook(secret)
const body = await req.text()
try {
const evt = wh.verify(body, {
'svix-id': headerPayload.get('svix-id')!,
'svix-timestamp': headerPayload.get('svix-timestamp')!,
'svix-signature': headerPayload.get('svix-signature')!,
})
// Handle event...
return new Response('OK', { status: 200 })
} catch {
return new Response('Invalid signature', { status: 400 })
}
}
Step 6: CI/CD Environment Promotion
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main, staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set environment
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "DEPLOY_ENV=production" >> $GITHUB_ENV
else
echo "DEPLOY_ENV=staging" >> $GITHUB_ENV
fi
- name: Deploy to Vercel
env:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets[format('CLERK_PK_{0}', env.DEPLOY_ENV)] }}
CLERK_SECRET_KEY: ${{ secrets[format('CLERK_SK_{0}', env.DEPLOY_ENV)] }}
run: vercel deploy --prod
Output
- Separate Clerk instances per environment (dev, staging, production)
- Environment-aware configuration with key validation
- Startup checks preventing key mismatches
- Per-environment webhook secrets
- CI/CD pipeline deploying correct keys per branch
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Key mismatch error | pk_test_ with sk_live_ | Ensure both keys from same Clerk instance |
| Webhook signature fails | Wrong secret for environment | Verify CLERK_WEBHOOK_SECRET matches instance |
| User not found | Querying wrong environment | Check you are hitting correct Clerk instance |
| OAuth redirect fails | Domain not configured | Add environment domain in Clerk Dashboard |
Examples
Vercel Preview Environment Setup
# Set env vars for Vercel preview deployments
vercel env add NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY preview
vercel env add CLERK_SECRET_KEY preview
Resources
Next Steps
Proceed to clerk-observability for monitoring and logging.
When not to use it
- →Do not use production keys in development mode
Prerequisites
Limitations
- →Requires one Clerk instance per environment
How it compares
This approach automates key validation and environment promotion compared to manual configuration management.
Compared to similar skills
clerk-multi-env-setup side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| clerk-multi-env-setup (this skill) | 1 | 27d | Review | Intermediate |
| nextjs-supabase-auth | 12 | 6mo | No flags | Intermediate |
| better-auth | 5 | 9mo | Review | Intermediate |
| auth-patterns | 7 | 7mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
nextjs-supabase-auth
davila7
Expert integration of Supabase Auth with Next.js App Router Use when: supabase auth next, authentication next.js, login supabase, auth middleware, protected route.
better-auth
mrgoonie
Implement authentication and authorization with Better Auth - a framework-agnostic TypeScript authentication framework. Features include email/password authentication with verification, OAuth providers (Google, GitHub, Discord, etc.), two-factor authentication (TOTP, SMS), passkeys/WebAuthn support, session management, role-based access control (RBAC), rate limiting, and database adapters. Use when adding authentication to applications, implementing OAuth flows, setting up 2FA/MFA, managing user sessions, configuring authorization rules, or building secure authentication systems for web applications.
auth-patterns
davepoon
This skill should be used when the user asks about "authentication in Next.js", "NextAuth", "Auth.js", "middleware auth", "protected routes", "session management", "JWT", "login flow", or needs guidance on implementing authentication and authorization in Next.js applications.
clerk-common-errors
jeremylongshore
Troubleshoot common Clerk errors and issues. Use when encountering authentication errors, SDK issues, or configuration problems with Clerk. Trigger with phrases like "clerk error", "clerk not working", "clerk authentication failed", "clerk issue", "fix clerk".
clerk-enterprise-rbac
jeremylongshore
Configure enterprise SSO, role-based access control, and organization management. Use when implementing SSO integration, configuring role-based permissions, or setting up organization-level controls. Trigger with phrases like "clerk SSO", "clerk RBAC", "clerk enterprise", "clerk roles", "clerk permissions", "clerk SAML".
clerk-performance-tuning
jeremylongshore
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".