SKILL.md
Nuxt Patterns
What Do You Need?
Task
Reference
Protect routes with middleware
references/nuxt-middleware.md
Auth in server API routes (Nitro)
references/server-api-routes.md
useAuth / useUser in components
references/composables.md
SSR-safe auth patterns
references/ssr-auth.md
References
Reference
Description
references/nuxt-middleware.md
Route protection, clerkMiddleware()
references/server-api-routes.md
Nitro server route auth
references/composables.md
useAuth, useUser, useClerk
references/ssr-auth.md
SSR hydration, server vs client
Setup
npm install @clerk/nuxt
.env:
NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
NUXT_CLERK_SECRET_KEY=sk_...
nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
})
This single line auto-configures middleware, plugins, and component auto-imports.
Mental Model
@clerk/nuxt auto-imports all Clerk components and composables — no explicit imports needed in <script setup>.
- Composables (
useAuth,useUser) — client-side reactive, inside<script setup>
- Server routes (
clerkClient) — Nitro server routes,event.context.auth
- Middleware (
clerkMiddleware) — auto-registered, useauth().protect()to lock routes
Minimal Pattern
<!-- pages/dashboard.vue -->
<script setup lang="ts">
definePageMeta({ middleware: 'auth' })
const { userId } = useAuth()
</script>
<template>
<Show when="signed-in">
<p>Hello {{ userId }}</p>
</Show>
</template>
definePageMeta({ middleware: 'auth' }) uses the built-in auth middleware from @clerk/nuxt.
Common Pitfalls
Symptom
Cause
Fix
Composables return undefined on server
useAuth is client-only
Use event.context.auth in server routes
Route not protected
Missing middleware: 'auth' meta
Add definePageMeta({ middleware: 'auth' })
clerkClient not available
Wrong import path
Import from @clerk/nuxt/server
Hydration mismatch
Rendering auth state before mounted
Wrap in <ClientOnly> or check isLoaded
Env vars not picked up
Wrong prefix
Nuxt requires NUXT_PUBLIC_ for public, NUXT_ for server
Org-Aware Pattern
<script setup lang="ts">
const { orgId, orgRole } = useAuth()
</script>
<template>
<div v-if="orgId">
<p>Org: {{ orgId }}</p>
<p v-if="orgRole === 'org:admin'">Admin panel</p>
</div>
<div v-else>
<OrganizationSwitcher />
</div>
</template>
See Also
clerk-setup- Initial Clerk install
clerk-custom-ui- Custom flows & appearance
clerk-orgs- B2B organizations