Astro Patterns
SDK: @clerk/astro v3+. Requires Astro 4.15+.
What Do You Need?
| 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 |
Mental Model
Astro has two rendering modes per page: SSR and static prerender. Clerk works differently in each:
- SSR pages — use
Astro.locals.auth()which is populated by the middleware - Static pages (
export const prerender = true) — Clerk middleware skips them; use client-side hooks in islands - Islands — React/Vue/Svelte components; use
useAuth()and other hooks from@clerk/astro/react
Request → clerkMiddleware() → SSR page → Astro.locals.auth() ↓ Island (.client) → useAuth() hook
Setup
astro.config.mjs
tsimport { defineConfig } from 'astro/config' import clerk from '@clerk/astro' export default defineConfig({ integrations: [clerk()], output: 'server', })
src/middleware.ts
tsimport { 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() })
SSR Page Auth
astro--- const { userId, orgId } = Astro.locals.auth() if (!userId) return Astro.redirect('/sign-in') --- <h1>Dashboard</h1>
Common Pitfalls
| 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 |
Import Map
| What | Import From |
|---|---|
clerkMiddleware, createRouteMatcher | @clerk/astro/server |
useAuth, useUser, UserButton | @clerk/astro/react |
Astro components (<SignIn>, etc.) | @clerk/astro/components |
Env Variables
# .env PUBLIC_CLERK_PUBLISHABLE_KEY=pk_... CLERK_SECRET_KEY=sk_...
Astro uses PUBLIC_ prefix for client-exposed variables (not NEXT_PUBLIC_).
See Also
clerk-setup- Initial Clerk installclerk-custom-ui- Custom flows & appearanceclerk-orgs- B2B organizations


