{"id":"c4586745-22ac-4e0e-98af-0f571d0d907a","shortId":"VVg9vT","kind":"skill","title":"nuxt","tagline":"Use when editing Nuxt apps, nuxt.config.ts, nuxt.config.js, .nuxt directories, useFetch, useAsyncData, Nitro server routes, SSR, SSG, or Vue server rendering with Nuxt.","description":"# Nuxt 3 Framework Skill\n\n<workflow>\n\n## Quick Reference\n\n### Page Component\n\n<example>\n\n```vue\n<!-- pages/users/[id].vue -->\n<script setup lang=\"ts\">\nconst route = useRoute();\nconst { data: user, error } = await useFetch(`/api/users/${route.params.id}`);\n\ndefinePageMeta({\n  layout: 'admin',\n  middleware: ['auth'],\n});\n\nuseHead({\n  title: () => user.value?.name ?? 'User',\n});\n</script>\n\n<template>\n  <div v-if=\"error\">Error: {{ error.message }}</div>\n  <div v-else-if=\"user\">\n    <h1>{{ user.name }}</h1>\n    <p>{{ user.email }}</p>\n  </div>\n</template>\n```\n\n</example>\n\n### Server API Routes\n\n<example>\n\n```typescript\n// server/api/users/[id].get.ts\nexport default defineEventHandler(async (event) => {\n  const id = getRouterParam(event, 'id');\n\n  const user = await db.users.findUnique({ where: { id } });\n\n  if (!user) {\n    throw createError({\n      statusCode: 404,\n      message: 'User not found',\n    });\n  }\n\n  return user;\n});\n\n// server/api/users.post.ts\nexport default defineEventHandler(async (event) => {\n  const body = await readBody(event);\n\n  const user = await db.users.create({ data: body });\n\n  return user;\n});\n```\n\n</example>\n\n### Composables\n\n<example>\n\n```typescript\n// composables/useAuth.ts\nexport function useAuth() {\n  const user = useState<User | null>('auth-user', () => null);\n  const isAuthenticated = computed(() => !!user.value);\n\n  async function login(credentials: Credentials) {\n    const { data } = await useFetch('/api/auth/login', {\n      method: 'POST',\n      body: credentials,\n    });\n    user.value = data.value;\n  }\n\n  async function logout() {\n    await useFetch('/api/auth/logout', { method: 'POST' });\n    user.value = null;\n    navigateTo('/login');\n  }\n\n  return { user, isAuthenticated, login, logout };\n}\n```\n\n</example>\n\n### Data Fetching\n\n<example>\n\n```vue\n<script setup lang=\"ts\">\n// Simple fetch\nconst { data, pending, error, refresh } = await useFetch('/api/items');\n\n// With options\nconst { data: items } = await useFetch('/api/items', {\n  query: { page: 1, limit: 10 },\n  pick: ['id', 'name'],  // Only include these fields\n  transform: (data) => data.items,\n  watch: [page],  // Re-fetch when page changes\n});\n\n// Lazy fetch (doesn't block navigation)\nconst { data, pending } = useLazyFetch('/api/slow-data');\n\n// useAsyncData for custom async operations\nconst { data } = await useAsyncData('key', () => {\n  return $fetch('/api/items');\n});\n</script>\n```\n\n</example>\n\n### Middleware\n\n<example>\n\n```typescript\n// middleware/auth.ts\nexport default defineNuxtRouteMiddleware((to, from) => {\n  const { isAuthenticated } = useAuth();\n\n  if (!isAuthenticated.value && to.path !== '/login') {\n    return navigateTo('/login');\n  }\n});\n\n// middleware/admin.ts (named middleware)\nexport default defineNuxtRouteMiddleware(() => {\n  const { user } = useAuth();\n\n  if (user.value?.role !== 'admin') {\n    throw createError({\n      statusCode: 403,\n      message: 'Forbidden',\n    });\n  }\n});\n```\n\n</example>\n\n### Plugins\n\n<example>\n\n```typescript\n// plugins/api.ts\nexport default defineNuxtPlugin(() => {\n  const api = $fetch.create({\n    baseURL: '/api',\n    onRequest({ options }) {\n      const token = useCookie('token');\n      if (token.value) {\n        options.headers = {\n          ...options.headers,\n          Authorization: `Bearer ${token.value}`,\n        };\n      }\n    },\n  });\n\n  return {\n    provide: { api },\n  };\n});\n\n// Usage: const { $api } = useNuxtApp();\n```\n\n</example>\n\n### Hybrid Rendering\n\n<example>\n\n```typescript\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  routeRules: {\n    '/': { prerender: true },\n    '/blog/**': { isr: 3600 },  // ISR: revalidate every hour\n    '/admin/**': { ssr: false },  // SPA mode\n    '/api/**': { cors: true },\n  },\n});\n```\n\n</example>\n\n### State Management\n\n<example>\n\n```typescript\n// With useState (SSR-safe)\nconst count = useState('counter', () => 0);\n\n// With Pinia\n// stores/user.ts\nexport const useUserStore = defineStore('user', () => {\n  const user = ref<User | null>(null);\n\n  async function fetch() {\n    user.value = await $fetch('/api/user');\n  }\n\n  return { user, fetch };\n});\n```\n\n</example>\n\n## Best Practices\n\n- Use `useFetch` for data fetching (handles SSR)\n- Use `useState` for SSR-safe reactive state\n- Use route rules for hybrid rendering strategies\n- Use server routes for backend logic\n- Use middleware for route guards\n- Use `definePageMeta` for page-level config\n\n</workflow>\n\n## References Index\n\n- **[Litestar-Vite Integration](references/litestar_vite.md)** — Backend integration with Litestar-Vite plugin.\n\n## Official References\n\n- <https://nuxt.com/docs/4.x/getting-started/introduction>\n- <https://nuxt.com/docs/4.x/getting-started/upgrade>\n- <https://nuxt.com/docs/4.x/api/composables/use-fetch>\n- <https://nuxt.com/docs/4.x/api/utils/define-nuxt-route-middleware>\n- <https://nitro.build/config/>\n- <https://github.com/nuxt/nuxt/releases>\n\n## Shared Styleguide Baseline\n\n- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.\n- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)\n- [TypeScript](https://github.com/cofin/flow/blob/main/templates/styleguides/languages/typescript.md)\n- Keep this skill focused on tool-specific workflows, edge cases, and integration details.\n\n<guardrails>\n## Guardrails\n\n- **Use `useFetch` or `useAsyncData` for data fetching** -- These composables are SSR-aware and prevent duplicate requests on the client. Never use plain `$fetch` in a component's top-level setup.\n- **Never access browser-only globals during SSR** -- Always check `import.meta.client` or use `onMounted` before accessing `window`, `document`, or `localStorage`.\n- **Use `server/` directory for sensitive operations** -- Keep database queries, API keys, and complex logic in Nitro server routes to ensure they never leak to the client.\n- **Always provide a unique key to `useAsyncData`** -- This is critical for proper hydration and preventing data mismatch between server and client.\n- **Prefer `useState` over local refs for global state** -- `useState` is SSR-safe and preserves state during hydration.\n</guardrails>\n\n<validation>\n## Validation Checkpoint\n\n- [ ] `useFetch` or `useAsyncData` is used for all top-level data fetching\n- [ ] No browser-only globals are accessed in the setup script without checks\n- [ ] Sensitive logic and API calls are moved to the `server/api/` directory\n- [ ] `useAsyncData` calls have unique and stable keys\n- [ ] `definePageMeta` is used for route-level guards and layouts\n- [ ] Components that require browser APIs are wrapped in `<ClientOnly>` or used within `onMounted`\n</validation>","tags":["nuxt","flow","cofin","agent-skills","ai-agents","beads","claude-code","codex","cursor","developer-tools","gemini-cli","opencode"],"capabilities":["skill","source-cofin","skill-nuxt","topic-agent-skills","topic-ai-agents","topic-beads","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-gemini-cli","topic-opencode","topic-plugin","topic-slash-commands","topic-spec-driven-development"],"categories":["flow"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cofin/flow/nuxt","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cofin/flow","source_repo":"https://github.com/cofin/flow","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (6,659 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:38.068Z","embedding":null,"createdAt":"2026-04-23T13:04:00.247Z","updatedAt":"2026-05-18T19:07:38.068Z","lastSeenAt":"2026-05-18T19:07:38.068Z","tsv":"'/admin':231 '/api':193,236 '/api/auth/login':119 '/api/auth/logout':131 '/api/user':272 '/blog':224 '/cofin/flow/blob/main/templates/styleguides/general.md)':372 '/cofin/flow/blob/main/templates/styleguides/languages/typescript.md)':376 '/config/':348 '/docs/4.x/api/composables/use-fetch':342 '/docs/4.x/api/utils/define-nuxt-route-middleware':345 '/docs/4.x/getting-started/introduction':336 '/docs/4.x/getting-started/upgrade':339 '/login':137,160,163 '/nuxt/nuxt/releases':351 '0':251 '3':25 '3600':226 '403':180 '404':65 'access':425,439,529 'admin':176 'alway':432,470 'api':38,190,209,212,453,539,568 'app':6 'async':47,76,110,126,266 'auth':103 'auth-us':102 'author':204 'await':56,80,85,117,129,270 'awar':404 'backend':304,325 'baselin':354 'baseurl':192 'bearer':205 'best':276 'bodi':79,88,122 'browser':427,525,567 'browser-on':426,524 'call':540,548 'case':387 'check':433,535 'checkpoint':510 'client':411,469,490 'complex':456 'compon':31,418,564 'compos':91,400 'composables/useauth.ts':93 'comput':108 'config':317 'const':49,54,78,83,97,106,115,154,170,189,196,211,247,256,260 'cor':237 'count':248 'counter':250 'createerror':63,178 'credenti':113,114,123 'critic':479 'data':87,116,143,281,397,485,521 'data.value':125 'databas':451 'db.users.create':86 'db.users.findunique':57 'default':45,74,150,168,187,219 'defineeventhandl':46,75 'definenuxtconfig':220 'definenuxtplugin':188 'definenuxtroutemiddlewar':151,169 'definepagemeta':312,554 'definestor':258 'detail':390 'directori':10,446,546 'document':441 'duplic':364,407 'edg':386 'edit':4 'ensur':463 'error':33 'error.message':34 'event':48,52,77,82 'everi':229 'export':44,73,94,149,167,186,218,255 'fals':233 'fetch':144,268,271,275,282,398,415,522 'fetch.create':191 'focus':380 'forbidden':182 'found':69 'framework':26 'function':95,111,127,267 'general':368 'generic':359 'get.ts':43 'getrouterparam':51 'github.com':350,371,375 'github.com/cofin/flow/blob/main/templates/styleguides/general.md)':370 'github.com/cofin/flow/blob/main/templates/styleguides/languages/typescript.md)':374 'github.com/nuxt/nuxt/releases':349 'global':429,497,527 'guard':310,561 'guardrail':391 'handl':283 'hour':230 'hybrid':214,297 'hydrat':482,508 'id':42,50,53,59 'import.meta.client':434 'index':319 'integr':323,326,389 'isauthent':107,140,155 'isauthenticated.value':158 'isr':225,227 'keep':377,450 'key':454,474,553 'language/framework':360 'layout':563 'leak':466 'level':316,422,520,560 'litestar':321,329 'litestar-vit':320,328 'local':494 'localstorag':443 'logic':305,457,537 'login':112,141 'logout':128,142 'manag':240 'messag':66,181 'method':120,132 'middlewar':146,166,307 'middleware/admin.ts':164 'middleware/auth.ts':148 'mismatch':486 'mode':235 'move':542 'name':165 'navigateto':136,162 'never':412,424,465 'nitro':13,459 'nitro.build':347 'nitro.build/config/':346 'null':101,105,135,264,265 'nuxt':1,5,9,23,24 'nuxt.com':335,338,341,344 'nuxt.com/docs/4.x/api/composables/use-fetch':340 'nuxt.com/docs/4.x/api/utils/define-nuxt-route-middleware':343 'nuxt.com/docs/4.x/getting-started/introduction':334 'nuxt.com/docs/4.x/getting-started/upgrade':337 'nuxt.config.js':8 'nuxt.config.ts':7,217 'offici':332 'onmount':437,575 'onrequest':194 'oper':449 'option':195 'options.headers':202,203 'page':30,315 'page-level':314 'pinia':253 'plain':414 'plugin':183,331 'plugins/api.ts':185 'post':121,133 'practic':277 'prefer':491 'prerend':222 'preserv':505 'prevent':406,484 'principl':369 'proper':481 'provid':208,471 'queri':452 'quick':28 'reactiv':291 'readbodi':81 'reduc':363 'ref':262,495 'refer':29,318,333 'references/litestar_vite.md':324 'render':21,215,298 'request':408 'requir':566 'return':70,89,138,161,207,273 'revalid':228 'role':175 'rout':15,39,294,302,309,461,559 'route-level':558 'routerul':221 'rule':295,361 'safe':246,290,503 'script':533 'sensit':448,536 'server':14,20,37,301,445,460,488 'server/api':545 'server/api/users':41 'server/api/users.post.ts':72 'setup':423,532 'share':352,356 'skill':27,367,379 'skill-nuxt' 'source-cofin' 'spa':234 'specif':384 'ssg':17 'ssr':16,232,245,284,289,403,431,502 'ssr-awar':402 'ssr-safe':244,288,501 'stabl':552 'state':239,292,498,506 'statuscod':64,179 'stores/user.ts':254 'strategi':299 'styleguid':353,357 'throw':62,177 'to.path':159 'token':197,199 'token.value':201,206 'tool':383 'tool-specif':382 'top':421,519 'top-level':420,518 'topic-agent-skills' 'topic-ai-agents' 'topic-beads' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-gemini-cli' 'topic-opencode' 'topic-plugin' 'topic-slash-commands' 'topic-spec-driven-development' 'true':223,238 'typescript':40,92,147,184,216,241,373 'uniqu':473,550 'usag':210 'use':2,278,285,293,300,306,311,355,392,413,436,444,515,556,573 'useasyncdata':12,395,476,513,547 'useauth':96,156,172 'usecooki':198 'usefetch':11,118,130,279,393,511 'usenuxtapp':213 'user':55,61,67,71,84,90,98,100,104,139,171,259,261,263,274 'user.email':36 'user.name':35 'user.value':109,124,134,174,269 'usest':99,243,249,286,492,499 'useuserstor':257 'valid':509 'vite':322,330 'vue':19,32,145 'window':440 'within':574 'without':534 'workflow':385 'wrap':570","prices":[{"id":"0fde40ea-065d-4ea9-9280-7091d27b594d","listingId":"c4586745-22ac-4e0e-98af-0f571d0d907a","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cofin","category":"flow","install_from":"skills.sh"},"createdAt":"2026-04-23T13:04:00.247Z"}],"sources":[{"listingId":"c4586745-22ac-4e0e-98af-0f571d0d907a","source":"github","sourceId":"cofin/flow/nuxt","sourceUrl":"https://github.com/cofin/flow/tree/main/skills/nuxt","isPrimary":false,"firstSeenAt":"2026-04-23T13:04:00.247Z","lastSeenAt":"2026-05-18T19:07:38.068Z"}],"details":{"listingId":"c4586745-22ac-4e0e-98af-0f571d0d907a","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cofin","slug":"nuxt","github":{"repo":"cofin/flow","stars":11,"topics":["agent-skills","ai-agents","beads","claude-code","codex","context-driven-development","cursor","developer-tools","gemini-cli","opencode","plugin","slash-commands","spec-driven-development","subagents","tdd","workflow"],"license":"apache-2.0","html_url":"https://github.com/cofin/flow","pushed_at":"2026-04-27T19:07:26Z","description":"Context-Driven Development toolkit for AI agents — spec-first planning, TDD workflow, and Beads integration.","skill_md_sha":"d2236295aff1f440ccf6757ee4c8d32e45151029","skill_md_path":"skills/nuxt/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cofin/flow/tree/main/skills/nuxt"},"layout":"multi","source":"github","category":"flow","frontmatter":{"name":"nuxt","description":"Use when editing Nuxt apps, nuxt.config.ts, nuxt.config.js, .nuxt directories, useFetch, useAsyncData, Nitro server routes, SSR, SSG, or Vue server rendering with Nuxt."},"skills_sh_url":"https://skills.sh/cofin/flow/nuxt"},"updatedAt":"2026-05-18T19:07:38.068Z"}}