PluginBench
Skill
Pass
Audit score 90

nuxt4-patterns

affaan-m/ecc

Nuxt 4 patterns for SSR hydration, route rules, lazy loading, and safe data fetching.

What is nuxt4-patterns?

Patterns and best practices for building Nuxt 4 apps with server-side rendering, hybrid rendering strategies, and client-server data synchronization. Use this when debugging hydration mismatches, configuring route-level rendering rules, optimizing performance, or implementing SSR-safe data fetching with useFetch and useAsyncData.

  • Prevent hydration mismatches by keeping first renders deterministic and moving browser-only logic behind onMounted, import.meta.client, or ClientOnly
  • 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, forwarding server data into the Nuxt payload to avoid double-fetches
  • Optimize performance with lazy loading, lazy hydration, and payload size trimming using pick and shallow reactivity
  • Handle lazy-loaded non-critical data with explicit loading UI and status checks

How to install nuxt4-patterns

npx skills add null --skill nuxt4-patterns
Claude Code
Cursor
Windsurf
Cline

How to use nuxt4-patterns

  1. 1.Review the hydration safety section and audit your components for Date.now(), Math.random(), or browser-only APIs in SSR-rendered templates
  2. 2.Replace top-level $fetch calls with await useFetch() or useAsyncData() in pages and components to enable server-side data forwarding
  3. 3.Define routeRules in nuxt.config.ts for each route group (prerender, swr, isr, ssr: false, cache) based on SEO and freshness needs
  4. 4.Wrap non-critical components with the Lazy prefix and conditionally render them with v-if to defer chunk loading
  5. 5.Use the review checklist to verify first SSR and hydrated renders match, data fetching is safe, and route rules align with requirements

Use cases

Good for
  • Debugging hydration mismatches between server HTML and client state in SSR apps
  • Setting rendering strategy per route group (marketing pages prerendered, APIs cached, admin dashboards client-only)
  • Fetching page data safely during SSR and hydration without duplicate requests or client-side race conditions
  • Lazy-loading below-the-fold components and interactive islands to reduce initial payload and improve Core Web Vitals
  • Configuring incremental static regeneration (ISR) or stale-while-revalidate (SWR) for frequently-accessed content
Who it's for
  • Nuxt 4 app developers building SSR or hybrid-rendered applications
  • Full-stack engineers optimizing performance and SEO for server-rendered pages
  • Teams managing route-level rendering and caching strategies across marketing, product, and API routes

nuxt4-patterns FAQ

What is the difference between useFetch and useAsyncData?

useFetch is for simple $fetch() calls and automatically forwards server-fetched data into the Nuxt payload. useAsyncData is for custom fetchers, multiple async sources, or when you need a stable cache key. Both are SSR-safe when awaited at the top level.

When should I use lazy: true or useLazyFetch?

Use lazy: true for non-critical data that should not block navigation. The component must handle status === 'pending' in the UI and display a loading state while data is being fetched.

How do I fix hydration mismatches?

Keep the first SSR render deterministic by avoiding Date.now(), Math.random(), and browser APIs in templates. Move browser-only logic behind onMounted(), import.meta.client, ClientOnly, or .client.vue components so the server and client produce identical markup.

What route rule should I use for my product catalog?

Use swr (stale-while-revalidate) with a maxAge like 3600 seconds to serve cached content instantly while revalidating in the background. Use isr for incremental static regeneration on supported platforms, or prerender if the catalog is small and rarely changes.

Does Nuxt automatically code-split pages?

Yes, Nuxt code-splits by route automatically. Use the Lazy prefix for non-critical components and conditionally render them with v-if to further optimize. For custom strategies, use defineLazyHydrationComponent() with visibility or idle detection.

Full instructions (SKILL.md)

Source of truth, from affaan-m/ecc.


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.vue component when the server cannot produce the same markup.
  • Use Nuxt's useRoute() composable, not the one from vue-router.
  • Do not use route.fullPath to drive SSR-rendered markup. URL fragments are client-only, which can create hydration mismatches.
  • Treat ssr: false as 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(), or useLazyAsyncData() for non-critical data that should not block navigation. Handle status === 'pending' in the UI.
  • Use server: false only for data that is not needed for SEO or the first paint.
  • Trim payload size with pick and 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 time
  • swr: serve cached content and revalidate in the background
  • isr: incremental static regeneration on supported platforms
  • ssr: false: client-rendered route
  • cache or redirect: 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 Lazy prefix to dynamically import non-critical components.
  • Conditionally render lazy components with v-if so 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 NuxtLink for 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 useFetch or useAsyncData, 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