clerk/clerk-astro-patterns
Astro patterns with Clerk — middleware, SSR pages, island components, astro protected page, clerk island component, astro API route auth, clerk astro SSR.'
npx skills add https://github.com/clerk/skills --skill clerk-astro-patterns
SDK: @clerk/astro v3+. Requires Astro 4.15+.
| Task | Reference |
|------|-----------|
| Configure middleware | references/middleware.md |
| Protect SSR pages | references/ssr-pages.md |
| Use Clerk in island components | references/island-components.md |
| Auth in API routes | references/api-routes.md |
| Use Clerk with React in Astro | references/astro-react.md |
Astro has two rendering modes per page: SSR and static prerender. Clerk works differently in each:
Astro.locals.auth() which is populated by the middlewareexport const prerender = true) — Clerk middleware skips them; use client-side hooks in islandsuseAuth() and other hooks from @clerk/astro/reactRequest → clerkMiddleware() → SSR page → Astro.locals.auth()
↓
Island (.client) → useAuth() hook
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
export default defineConfig({
integrations: [clerk()],
output: 'server',
})
import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)'])
export const onRequest = clerkMiddleware((auth, context, next) => {
if (isProtectedRoute(context.request) && !auth().userId) {
return auth().redirectToSignIn()
}
return next()
})
---
const { userId, orgId } = Astro.locals.auth()
if (!userId) return Astro.redirect('/sign-in')
---
<h1>Dashboard</h1>
| Symptom | Cause | Fix |
|---------|-------|-----|
| Astro.locals.auth is undefined | Missing middleware | Add clerkMiddleware to src/middleware.ts |
| Auth works in dev but not production | output: 'static' globally | Set output: 'server' or hybrid for protected pages |
| Static page has no auth | Prerendered pages skip middleware | Use export const prerender = false or move to island |
| Island not reactive to sign-in | Missing client:load directive | Add client:load to the island component |
| What | Import From |
|------|-------------|
| clerkMiddleware, createRouteMatcher | @clerk/astro/server |
| useAuth, useUser, UserButton | @clerk/astro/react |
| Astro components (<SignIn>, etc.) | @clerk/astro/components |
# .env
PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
Astro uses PUBLIC_ prefix for client-exposed variables (not NEXT_PUBLIC_).
clerk-setup - Initial Clerk installclerk-custom-ui - Custom flows & appearanceclerk-orgs - B2B organizationsTake clerk/clerk-astro-patterns from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.