nuxt4-patterns
affaan-m/everything-claude-code
Nuxt 4 patterns for SSR, hydration safety, route rules, and data fetching.
What is nuxt4-patterns?
Reference patterns for building Nuxt 4 apps with server-side rendering, hybrid rendering strategies, and client-server data synchronization. Use when debugging hydration mismatches, configuring route-level rendering rules, optimizing performance, or implementing SSR-safe data fetching.
- Prevent hydration mismatches by keeping first renders deterministic and moving browser-only logic behind lifecycle hooks or client-only components
- Configure route-level rendering strategies (prerender, SWR, ISR, client-only) via routeRules in nuxt.config.ts
- Implement SSR-safe data fetching with useFetch and useAsyncData that forward server data into the Nuxt payload
- Lazy-load non-critical components and data with Lazy prefix, useLazyFetch, and useLazyAsyncData to avoid blocking navigation
- Optimize payload size and performance through selective data picking, lazy hydration strategies, and meaningful route boundaries
How to install nuxt4-patterns
npx skills add https://github.com/affaan-m/everything-claude-code --skill nuxt4-patternsHow to use nuxt4-patterns
- 1.Identify hydration issues by comparing server HTML and client state; move browser-only logic to onMounted(), import.meta.client, or ClientOnly components
- 2.Replace top-level $fetch calls in pages with await useFetch() or useAsyncData() to enable server-side fetching and payload hydration
- 3.Define routeRules in nuxt.config.ts to set rendering strategy (prerender, swr, isr, ssr: false) per route group based on SEO and freshness needs
- 4.Wrap non-critical components with Lazy prefix and conditionally render with v-if to defer chunk loading until needed
- 5.Use lazy: true or useLazyFetch() for non-blocking data, handle status === 'pending' in UI, and trim payload with pick option
Use cases
- Fixing hydration mismatches caused by Date.now(), Math.random(), or browser APIs in SSR-rendered templates
- Deciding rendering strategy for different route groups: marketing pages with prerender, product catalogs with SWR, admin dashboards with client-only rendering
- Fetching page data on the server and hydrating it on the client without duplicate requests using useFetch or useAsyncData
- Lazy-loading below-the-fold components or non-critical interactive UI to reduce initial payload and improve navigation speed
- Configuring cache headers and revalidation behavior for API routes and dynamic content
- Nuxt 4 developers building SSR or hybrid-rendered applications
- Full-stack engineers optimizing performance and SEO in Nuxt apps
- Teams managing multi-strategy rendering across marketing, product, and admin sections
nuxt4-patterns FAQ
useFetch is for simple $fetch() calls and automatically forwards server-fetched data into the Nuxt payload. useAsyncData is for custom fetchers, composing multiple async sources, or when you need a stable cache key. Both are SSR-safe when awaited at the top level.
Keep the first render deterministic by avoiding Date.now(), Math.random(), and browser APIs in SSR templates. Move browser-only logic behind onMounted(), import.meta.client, ClientOnly components, or .client.vue files so the server and client produce identical markup.
Use ssr: false for truly client-only routes like admin dashboards or user-specific pages that do not need SEO. Do not use it as a default fix for hydration mismatches; instead, make the first render deterministic.
Lazy components (Lazy prefix) defer code-splitting and loading until the component is rendered. Lazy hydration defers interactive hydration until the component is visible or idle, reducing initial hydration work while keeping the HTML in the DOM.
routeRules in nuxt.config.ts define rendering and caching strategy per route group: prerender for static HTML, swr for background revalidation, isr for incremental regeneration, ssr: false for client-only routes, and cache for API response headers.
Full instructions (SKILL.md)
Source of truth, from affaan-m/everything-claude-code.
name: nuxt4-patterns description: Nuxt 4 app patterns for hydration safety, performance, route rules, lazy loading, and SSR-safe data fetching with useFetch and useAsyncData. metadata: origin: ECC
Nuxt 4 Patterns
Use when building or debugging Nuxt 4 apps with SSR, hybrid rendering, route rules, or page-level data fetching.
When to Activate
- Hydration mismatches between server HTML and client state
- Route-level rendering decisions such as prerender, SWR, ISR, or client-only sections
- Performance work around lazy loading, lazy hydration, or payload size
- Page or component data fetching with
useFetch,useAsyncData, or$fetch - Nuxt routing issues tied to route params, middleware, or SSR/client differences
Hydration Safety
- Keep the first render deterministic. Do not put
Date.now(),Math.random(), browser-only APIs, or storage reads directly into SSR-rendered template state. - Move browser-only logic behind
onMounted(),import.meta.client,ClientOnly, or a.client.vuecomponent when the server cannot produce the same markup. - Use Nuxt's
useRoute()composable, not the one fromvue-router. - Do not use
route.fullPathto drive SSR-rendered markup. URL fragments are client-only, which can create hydration mismatches. - Treat
ssr: falseas an escape hatch for truly browser-only areas, not a default fix for mismatches.
Data Fetching
- Prefer
await useFetch()for SSR-safe API reads in pages and components. It forwards server-fetched data into the Nuxt payload and avoids a second fetch on hydration. - Use
useAsyncData()when the fetcher is not a simple$fetch()call, when you need a custom key, or when you are composing multiple async sources. - Give
useAsyncData()a stable key for cache reuse and predictable refresh behavior. - Keep
useAsyncData()handlers side-effect free. They can run during SSR and hydration. - Use
$fetch()for user-triggered writes or client-only actions, not top-level page data that should be hydrated from SSR. - Use
lazy: true,useLazyFetch(), oruseLazyAsyncData()for non-critical data that should not block navigation. Handlestatus === 'pending'in the UI. - Use
server: falseonly for data that is not needed for SEO or the first paint. - Trim payload size with
pickand prefer shallower payloads when deep reactivity is unnecessary.
const route = useRoute()
const { data: article, status, error, refresh } = await useAsyncData(
() => `article:${route.params.slug}`,
() => $fetch(`/api/articles/${route.params.slug}`),
)
const { data: comments } = await useFetch(`/api/articles/${route.params.slug}/comments`, {
lazy: true,
server: false,
})
Route Rules
Prefer routeRules in nuxt.config.ts for rendering and caching strategy:
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/products/**': { swr: 3600 },
'/blog/**': { isr: true },
'/admin/**': { ssr: false },
'/api/**': { cache: { maxAge: 60 * 60 } },
},
})
prerender: static HTML at build timeswr: serve cached content and revalidate in the backgroundisr: incremental static regeneration on supported platformsssr: false: client-rendered routecacheorredirect: Nitro-level response behavior
Pick route rules per route group, not globally. Marketing pages, catalogs, dashboards, and APIs usually need different strategies.
Lazy Loading and Performance
- Nuxt already code-splits pages by route. Keep route boundaries meaningful before micro-optimizing component splits.
- Use the
Lazyprefix to dynamically import non-critical components. - Conditionally render lazy components with
v-ifso the chunk is not loaded until the UI actually needs it. - Use lazy hydration for below-the-fold or non-critical interactive UI.
<template>
<LazyRecommendations v-if="showRecommendations" />
<LazyProductGallery hydrate-on-visible />
</template>
- For custom strategies, use
defineLazyHydrationComponent()with a visibility or idle strategy. - Nuxt lazy hydration works on single-file components. Passing new props to a lazily hydrated component will trigger hydration immediately.
- Use
NuxtLinkfor internal navigation so Nuxt can prefetch route components and generated payloads.
Review Checklist
- First SSR render and hydrated client render produce the same markup
- Page data uses
useFetchoruseAsyncData, not top-level$fetch - Non-critical data is lazy and has explicit loading UI
- Route rules match the page's SEO and freshness requirements
- Heavy interactive islands are lazy-loaded or lazily hydrated
Related skills
More from affaan-m/everything-claude-code and the wider catalog.
security-review
Security checklist and patterns for authentication, input validation, secrets, and sensitive features.
golang-patterns
Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable applications.
coding-standards
Baseline coding conventions for naming, readability, immutability, and quality across projects.
frontend-patterns
React and Next.js patterns for components, state management, performance, and modern frontend practices.
backend-patterns
REST/GraphQL API design, database optimization, and server-side patterns for Node.js, Express, and Next.js.
golang-testing
Go testing patterns: table-driven tests, subtests, benchmarks, fuzzing, and TDD methodology.