{"id":83795,"plugin_id":"plugin_asdk_app_6ae4e34683b08191933207035aa0d3ac","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-11-06T00:16:32.350Z","digest":"4361fceaea861a49e44942b43194b6a769499c8829969d8f61b12a867c08e724","against":null,"payload":{"description":"Astro patterns with Clerk — middleware, SSR pages, island components, API routes, static vs SSR rendering. Triggers on: astro clerk, clerk astro middleware, astro protected page, clerk island component, astro API route auth, clerk astro SSR.","included_files":[{"relative_path":"evals/evals.json","size_in_bytes":5743},{"relative_path":"references/api-routes.md","size_in_bytes":2009},{"relative_path":"references/astro-react.md","size_in_bytes":2295},{"relative_path":"references/island-components.md","size_in_bytes":1723},{"relative_path":"references/middleware.md","size_in_bytes":2021},{"relative_path":"references/ssr-pages.md","size_in_bytes":1811},{"relative_path":"templates/astro-basic-auth/astro.config.mjs","size_in_bytes":229},{"relative_path":"templates/astro-basic-auth/package.json","size_in_bytes":227},{"relative_path":"templates/astro-basic-auth/src/layouts/Layout.astro","size_in_bytes":522},{"relative_path":"templates/astro-basic-auth/src/middleware.ts","size_in_bytes":98},{"relative_path":"templates/astro-basic-auth/src/pages/index.astro","size_in_bytes":260},{"relative_path":"templates/astro-basic-auth/src/pages/sign-in.astro","size_in_bytes":135},{"relative_path":"templates/astro-basic-auth/tsconfig.json","size_in_bytes":42}],"name":"clerk-astro-patterns","skill_md_contents":"---\nname: clerk-astro-patterns\ndescription: 'Astro patterns with Clerk — middleware, SSR pages, island components,\n  API routes, static vs SSR rendering. Triggers on: astro clerk, clerk astro middleware,\n  astro protected page, clerk island component, astro API route auth, clerk astro\n  SSR.'\nlicense: MIT\nallowed-tools: WebFetch\nmetadata:\n  author: clerk\n  version: 1.0.0\n---\n\n# Astro Patterns\n\nSDK: `@clerk/astro` v4+. Requires Astro 5+.\n\n## What Do You Need?\n\n| Task | Reference |\n|------|-----------|\n| Configure middleware (bare `clerkMiddleware()`, checks per page) | references/middleware.md |\n| Protect SSR pages | references/ssr-pages.md |\n| Use Clerk in island components | references/island-components.md |\n| Auth in API routes | references/api-routes.md |\n| Use Clerk with React in Astro | references/astro-react.md |\n\n## Mental Model\n\nAstro has two rendering modes per page: **SSR** and **static prerender**. Clerk works differently in each:\n\n- **SSR pages** — use `Astro.locals.auth()` which is populated by the middleware\n- **Static pages** (`export const prerender = true`) — Clerk middleware skips them; use client-side hooks in islands\n- **Islands** — React/Vue/Svelte components; use `useAuth()` and other hooks from `@clerk/astro/react`\n\n```\nRequest → clerkMiddleware() → SSR page → Astro.locals.auth()\n                                ↓\n                         Island (.client) → useAuth() hook\n```\n\n## Setup\n\n### astro.config.mjs\n\n```ts\nimport { defineConfig } from 'astro/config'\nimport clerk from '@clerk/astro'\n\nexport default defineConfig({\n  integrations: [clerk()],\n  output: 'server',\n})\n```\n\n### src/middleware.ts\n\n```ts\nimport { clerkMiddleware } from '@clerk/astro/server'\n\nexport const onRequest = clerkMiddleware()\n```\n\nThe middleware populates `Astro.locals.auth()`. Each page and API route checks for itself. `createRouteMatcher` was removed in `@clerk/astro` 4.0 (deprecated in 3.x). Don't add it. Existing uses must move to page and API-route checks before upgrading. See the [Astro `clerkMiddleware()` reference](https://clerk.com/docs/reference/astro/clerk-middleware).\n\n## SSR Page Auth\n\n```astro\n---\nconst { userId, orgId } = Astro.locals.auth()\nif (!userId) return Astro.redirect('/sign-in')\n---\n\n<h1>Dashboard</h1>\n```\n\n## API Route Auth\n\n```ts\n// src/pages/api/data.ts\nimport type { APIRoute } from 'astro'\n\nexport const GET: APIRoute = ({ locals }) => {\n  const { userId } = locals.auth()\n  if (!userId) return new Response('Unauthorized', { status: 401 })\n\n  return Response.json({ userId })\n}\n```\n\n## Common Pitfalls\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `Astro.locals.auth` is undefined | Missing middleware | Add `clerkMiddleware` to `src/middleware.ts` |\n| Auth works in dev but not production | `output: 'static'` globally | Set `output: 'server'` or `hybrid` for protected pages |\n| Static page has no auth | Prerendered pages skip middleware | Use `export const prerender = false` or move to island |\n| Island not reactive to sign-in | Missing `client:load` directive | Add `client:load` to the island component |\n\n## Import Map\n\n| What | Import From |\n|------|-------------|\n| `clerkMiddleware`, `clerkClient` | `@clerk/astro/server` |\n| `useAuth`, `UserButton` (no `useUser`) | `@clerk/astro/react` |\n| `$userStore`, `$authStore` | `@clerk/astro/client` |\n| Astro components (`<SignIn>`, etc.) | `@clerk/astro/components` |\n\n## Env Variables\n\n```\n# .env\nPUBLIC_CLERK_PUBLISHABLE_KEY=pk_...\nCLERK_SECRET_KEY=sk_...\n```\n\nAstro uses `PUBLIC_` prefix for client-exposed variables (not `NEXT_PUBLIC_`).\n\n## See Also\n\n- `clerk-setup` - Initial Clerk install\n- `clerk-custom-ui` - Custom flows & appearance\n- `clerk-orgs` - B2B organizations\n\n## Docs\n\n[Astro SDK](https://clerk.com/docs/astro/getting-started/quickstart)\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}