All skills
onmax avatar

/nuxt

@de09c7b official
by Maxonmax/nuxt-skills715 stars
38

Nuxt full-stack Vue framework with SSR, auto-imports, and file-based routing. Use when working with Nuxt apps, server routes, useFetch, middleware, or hybrid rendering.

Use this Skill: https://skilld.dev/gh/onmax/nuxt-skills/nuxt

This session only. Nothing lands on disk.

referencescore-data-fetching.md

≈2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Data Fetching

Nuxt provides composables for SSR-friendly data fetching that prevent double-fetching and handle hydration.

Overview

  • $fetch - Basic fetch utility (use for client-side events)
  • useFetch - SSR-safe wrapper around $fetch (use for component data)
  • useAsyncData - SSR-safe wrapper for any async function
  • createUseFetch / createUseAsyncData - factories to build typed custom composables with baked-in defaults

useFetch

Primary composable for fetching data in components:

<script setup lang="ts">
const { data, status, error, refresh, clear } = await useFetch('/api/posts')
</script>

<template>
  <div v-if="status === 'pending'">Loading...</div>
  <div v-else-if="error">Error: {{ error.message }}</div>
  <div v-else>
    <article v-for="post in data" :key="post.id">
      {{ post.title }}
    </article>
  </div>
</template>

With Options

const { data } = await useFetch('/api/posts', {
  // Query parameters
  query: { page: 1, limit: 10 },
  // Request body (for POST/PUT)
  body: { title: 'New Post' },
  // HTTP method
  method: 'POST',
  // Only pick specific fields
  pick: ['id', 'title'],
  // Transform response
  transform: (posts) => posts.map(p => ({ ...p, slug: slugify(p.title) })),
  // Custom key for caching
  key: 'posts-list',
  // Don't fetch on server
  server: false,
  // Don't block navigation
  lazy: true,
  // Don't fetch immediately
  immediate: false,
  // Default value
  default: () => [],
})

Reactive Parameters

<script setup lang="ts">
const page = ref(1)
const { data } = await useFetch('/api/posts', {
  query: { page }, // Automatically refetches when page changes
})
</script>

Computed URL

<script setup lang="ts">
const id = ref(1)
const { data } = await useFetch(() => `/api/posts/${id.value}`)
// Refetches when id changes
</script>

useAsyncData

For wrapping any async function:

<script setup lang="ts">
const { data, error } = await useAsyncData('user', () => {
  return myCustomFetch('/user/profile')
})
</script>

Multiple Requests

<script setup lang="ts">
const { data } = await useAsyncData('cart', async () => {
  const [coupons, offers] = await Promise.all([
    $fetch('/api/coupons'),
    $fetch('/api/offers'),
  ])
  return { coupons, offers }
})
</script>

Custom Fetchers: createUseFetch / createUseAsyncData

Factory macros that produce a fully typed custom composable with pre-defined options. Must be an exported declaration inside app/composables/ (Nuxt injects dedup keys at build time).

// app/composables/useAPI.ts
export const useAPI = createUseFetch({
  baseURL: 'https://api.nuxt.com',
  // shared interceptors, headers, etc.
  onResponseError({ response }) {
    if (response.status === 401) navigateTo('/login')
  },
})
<script setup lang="ts">
// Same signature/return as useFetch, with defaults applied
const { data } = await useAPI('/modules')
// Caller can still override any option
const { data: other } = await useAPI('/modules', { baseURL: 'https://other.com' })
</script>

Default vs Override mode:

// Plain object → options act as DEFAULTS (caller can override)
export const useAPI = createUseFetch({ baseURL: '/api', lazy: true })

// Function → options OVERRIDE caller's (enforce auth/baseURL)
export const useAPI = createUseFetch(callerOptions => ({
  baseURL: 'https://api.nuxt.com', // always enforced
}))

Use the function form when you need useNuxtApp() (called in setup context, not module scope):

// app/composables/useAPI.ts
export const useAPI = createUseFetch(callerOptions => ({
  $fetch: useNuxtApp().$api as typeof $fetch,
  ...callerOptions,
}))

createUseAsyncData works identically for wrapping arbitrary async functions:

// app/composables/useCachedData.ts
export const useCachedData = createUseAsyncData({
  getCachedData(key, nuxtApp) {
    return nuxtApp.payload.data[key] ?? nuxtApp.static.data[key]
  },
})

Replaces the old "don't await your custom useFetch wrapper" caveat — use these factories instead of hand-rolled wrappers.

$fetch

For client-side events (form submissions, button clicks):

<script setup lang="ts">
async function submitForm() {
  const result = await $fetch('/api/submit', {
    method: 'POST',
    body: { name: 'John' },
  })
}
</script>

Important: Don't use $fetch alone in setup for initial data - it will fetch twice (server + client). Use useFetch or useAsyncData instead.

Return Values

All composables return:

Property Type Description
data Ref<T> Fetched data (undefined until resolved)
error Ref<Error> Error if request failed
status Ref<'idle' | 'pending' | 'success' | 'error'> Request status
pending Ref<boolean> Whether a request is in progress
refresh () => Promise Refetch data
execute () => Promise Alias for refresh
clear () => void Reset to default/idle and cancel pending requests

Prefer status over pending for fine-grained state. useFetch no longer accepts a top-level timeout option (still available on useAsyncData); use a cache option ('default', 'no-store', false, etc.) for Fetch cache control.

Lazy Fetching

Don't block navigation:

<script setup lang="ts">
// Using lazy option
const { data, status } = await useFetch('/api/posts', { lazy: true })

// Or use lazy variants
const { data, status } = await useLazyFetch('/api/posts')
const { data, status } = await useLazyAsyncData('key', fetchFn)
</script>

Refresh & Watch

<script setup lang="ts">
const category = ref('tech')

const { data, refresh } = await useFetch('/api/posts', {
  query: { category },
  // Auto-refresh when category changes
  watch: [category],
})

// Manual refresh
const refreshData = () => refresh()
</script>

Caching

Data is cached by key. Share data across components:

<script setup lang="ts">
// In component A
const { data } = await useFetch('/api/user', { key: 'current-user' })

// In component B - uses cached data
const { data } = useNuxtData('current-user')
</script>

Refresh cached data globally:

// Refresh specific key
await refreshNuxtData('current-user')

// Refresh all data
await refreshNuxtData()

// Clear cached data
clearNuxtData('current-user')

Interceptors

const { data } = await useFetch('/api/auth', {
  onRequest({ options }) {
    options.headers.set('Authorization', `Bearer ${token}`)
  },
  onRequestError({ error }) {
    console.error('Request failed:', error)
  },
  onResponse({ response }) {
    // Process response
  },
  onResponseError({ response }) {
    if (response.status === 401) {
      navigateTo('/login')
    }
  },
})

Passing Headers (SSR)

useFetch automatically proxies cookies/headers from client to server. For $fetch:

<script setup lang="ts">
const headers = useRequestHeaders(['cookie'])
const data = await $fetch('/api/user', { headers })
</script>
<!-- Source references: - https://nuxt.com/docs/4.x/getting-started/data-fetching - https://nuxt.com/docs/4.x/api/composables/use-fetch - https://nuxt.com/docs/4.x/api/composables/use-async-data - https://nuxt.com/docs/4.x/api/composables/create-use-fetch - https://nuxt.com/docs/4.x/api/composables/create-use-async-data - https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch -->

Source: SKILL.md on GitHub

No alerts9d5 checks · Risk SAFE
  • Gen Agent Trust Hub9d

    This skill provides a comprehensive technical reference for the Nuxt full-stack framework, including documentation on directory structure, routing, data fetching, and deployment. No security issues or malicious patterns were detected.

  • Socket9d

    No alerts

  • Snyk9d

    Risk: LOW · No issues

  • Runlayer7mo

    8 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at de09c7b. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated last week
Other metadata
metadata
{
  "author": "Anthony Fu",
  "version": "2026.6.22",
  "source": "Generated from https://github.com/nuxt/nuxt, scripts located at https://github.com/antfu/skills"
}

README badge

README badge for onmax/nuxt-skills/nuxt

Provides patterns and reference files for Nuxt 4.3+ projects, covering server routes with h3 validation, file-based routing, middleware, plugins, and Nuxt composables. Use this when building API endpoints, setting up pages and layouts, or working with Nuxt-specific features like auto-imports and route guards.

Generated from the current SKILL.md.

Does this skill cover Nuxt 3 or only Nuxt 4+?
This skill targets Nuxt 4.3+ only. It includes patterns specific to Nuxt 4, such as typed router and getRouterParam, and does not cover Nuxt 2 or 3 conventions.
Does this skill include guidance for h3 and Nitro?
Yes. The skill covers h3 v1 helpers (validation, WebSocket, SSE) and nitropack v2 patterns for server routes and middleware.
Does this cover UI components like buttons or forms?
No. The skill covers Nuxt-specific components (NuxtLink, NuxtImg, NuxtTime) but delegates UI component libraries to the separate nuxt-ui skill.
Can I use this skill for creating Nuxt modules?
No. For module development, use the nuxt-modules skill instead. This skill focuses on building applications with Nuxt 4+.
Does this skill include database or content management guidance?
No. For databases, use the nuxthub skill; for content-driven sites, use the nuxt-content skill.

Generated from the current SKILL.md. These answers refresh after source changes.