Nuxt
Verified@ivangdavila
npx machina-cli add skill @ivangdavila/nuxt --openclawNuxt 3 Patterns
Data Fetching
useFetchdeduplicates and caches requests during SSR — use it in components, not$fetchwhich fetches twice (server + client)$fetchis for event handlers and server routes only — in<script setup>it causes hydration mismatchesuseFetchruns on server during SSR — checkprocess.serverif you need client-only data- Add
keyoption touseFetchwhen URL params change but path stays same — without it, cache returns stale data useLazyFetchdoesn't block navigation — use for non-critical data, but handle the pending state
Hydration Traps
Date.now()orMath.random()in templates cause hydration mismatches — compute once in setup or use<ClientOnly>- Browser-only APIs (localStorage, window) crash SSR — wrap in
onMountedorprocess.clientcheck - Conditional rendering based on client-only state mismatches — use
<ClientOnly>component with fallback v-ifwith async data shows flash of wrong content — usev-showor skeleton states instead
Auto-imports
- Components in
components/auto-import with folder-based naming —components/UI/Button.vuebecomes<UIButton> - Composables in
composables/must be nameduse*for auto-import —utils.tsexports won't auto-import - Server utils in
server/utils/auto-import in server routes only — not available in client code - Disable auto-imports per-file with
// @ts-nocheckor explicitly import to avoid naming collisions
Server Routes
- Files in
server/api/become API routes —server/api/users.get.tshandles GET /api/users - Method suffix (
.get.ts,.post.ts) is required for method-specific handlers — without it, handles all methods getQuery(event)for query params,readBody(event)for POST body — don't accessevent.reqdirectly- Return value is auto-serialized to JSON — throw
createError({ statusCode: 404 })for errors
State Management
useStateis SSR-safe and persists across navigation — regularref()resets on each pageuseStatekey must be unique app-wide — collisions silently share state between components- Pinia stores need
storeToRefs()to keep reactivity when destructuring — without it, values lose reactivity - Don't initialize state with browser APIs in
useStatedefault — it runs on server too
Middleware
- Global middleware in
middleware/with.global.tssuffix runs on every route — order is alphabetical - Route middleware defined in
definePageMetaruns after global — use for auth checks on specific pages navigateTo()in middleware must be returned — forgettingreturncontinues to the original route- Server middleware in
server/middleware/runs on all server requests including API routes
Configuration
runtimeConfigfor server secrets,runtimeConfig.publicfor client-safe values — env vars override withNUXT_prefixapp.config.tsfor build-time config that doesn't need env vars — it's bundled into the appnuxt.config.tschanges require restart —app.config.tschanges hot-reload
SEO and Meta
useSeoMetafor standard meta tags — type-safe and handles og:/twitter: prefixes automaticallyuseHeadfor custom tags, scripts, and links — more flexible but no type safety for meta names- Meta in
definePageMetais static — useuseSeoMetain setup for dynamic values titleTemplateinnuxt.configfor consistent titles —%s - My Sitepattern
Plugins
- Plugins run before app creation — use
nuxtApp.hook('app:created')for post-creation logic providein plugins makes values available viauseNuxtApp()— but composables are cleaner- Plugin order: numbered prefixes (
01.plugin.ts) run first, then alphabetical — dependencies need explicit ordering - Client-only plugins:
.client.tssuffix — server-only:.server.tssuffix
Build and Deploy
nuxt generatecreates static files — but API routes won't work without a servernuxt buildcreates server bundle — deploy the.outputdirectory- ISR with
routeRules:'/blog/**': { isr: 3600 }— caches pages for 1 hour - Prerender specific routes:
routeRules: { '/about': { prerender: true } }— builds static HTML at build time
Overview
Nuxt 3 patterns guide you through building Vue 3 SSR/SSG applications with robust data fetching, hydration safety, and server-side patterns. It covers fetching strategies, auto-imports, server routes, state management, middleware, configuration, and SEO to deliver production-grade apps.
How This Skill Works
Nuxt automatically imports components from components/ and composables from composables/. Use useFetch for SSR data which deduplicates requests; avoid $fetch in components to prevent double-fetches. API endpoints live in server/api with method-specific files (e.g., .get.ts, .post.ts) and data is accessed via getQuery/readBody; responses auto-serialize to JSON. Use SEO helpers like useSeoMeta/useHead for dynamic meta and ensure hydration safety by avoiding browser-only code in templates and using ClientOnly where appropriate.
When to Use It
- You need SSR/SSG pages that fetch data during rendering with useFetch.
- You want to prevent hydration mismatches caused by dynamic values in templates.
- You want clean auto-imports for components and composables to speed up development.
- You are building a server API under server/api with method-specific handlers.
- You need dynamic SEO/meta handling with useSeoMeta or useHead.
Quick Start
- Step 1: Structure your project with components/, composables/, server/ and server/api/, and start using useFetch for SSR data.
- Step 2: Create server/api/ routes with method-specific files (e.g., .get.ts) and access query/body with getQuery/readBody.
- Step 3: Add SEO with useSeoMeta/useHead and ensure hydration safety by avoiding browser-only code in templates; restart dev server after config changes.
Best Practices
- Use useFetch with deduplication and caching; avoid using $fetch in components to prevent double-fetch.
- Add a unique key to useFetch when URL params change to avoid stale caches.
- Compute Date.now() or Math.random() in setup or use ClientOnly to prevent hydration mismatches.
- Wrap browser-only APIs with onMounted or process.client; use ClientOnly for client-only UI.
- Leverage auto-imports: components in components/ auto-import as <UIButton> for UI/Button.vue; composables named use* auto-import; server utils only in server; disable auto-import per-file with // @ts-nocheck when needed.
Example Use Cases
- A Nuxt 3 page that fetches article data with useFetch during SSR and updates on client navigation using a key.
- A server/api/users.get.ts that returns a list of users and uses createError to handle 404 or other errors.
- A page that dynamically sets SEO meta using useSeoMeta/useHead based on fetched data.
- An auto-imported UI component <UIButton> sourced from components/UI/Button.vue used within a page.
- Global middleware in middleware/ with a .global.ts file that runs on every route.