Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Nuxt 4+ development patterns: server routes, file-based routing, middleware, composables, and h3 v1 / nitropack v2.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/nuxt-composables.md
1# Nuxt Composables & Utilities23## When to Use45Working with Nuxt-specific composables, URL handling, navigation, or data fetching.67## URL & Request Handling89### useRequestURL()1011**ALWAYS use `useRequestURL()` instead of `window.origin` or `window.location`:**1213```ts14// ✅ Correct - works SSR + client15const url = useRequestURL()16console.log(url.origin) // https://example.com17console.log(url.pathname) // /users/12318console.log(url.search) // ?tab=profile1920// ❌ Wrong - breaks on SSR, not available server-side21const origin = window.origin22const path = window.location.pathname23```2425**Why:** `window` is undefined during SSR. `useRequestURL()` works everywhere.2627### useRequestURL() Patterns2829```ts30// Get full URL31const url = useRequestURL()32const fullUrl = url.href // https://example.com/users/123?tab=profile3334// Get origin (base URL)35const baseUrl = url.origin // https://example.com3637// Get path38const path = url.pathname // /users/1233940// Get query params (use useRoute() instead for better typing)41const params = url.searchParams42const tab = params.get('tab') // 'profile'4344// Build absolute URL45const apiUrl = `${url.origin}/api/users`46```4748## Navigation Composables4950### navigateTo()5152```ts53// Navigate to route54await navigateTo('/about')5556// Type-safe navigation57await navigateTo({ name: '/users/[userId]', params: { userId: '123' } })5859// External URL60await navigateTo('https://nuxt.com', { external: true })6162// Replace history63await navigateTo('/login', { replace: true })6465// Open in new tab66await navigateTo('/docs', { open: { target: '_blank' } })6768// Server-side redirect69return navigateTo('/login') // in middleware or server route70```7172### useRouter()7374```ts75const router = useRouter()7677// Navigate78router.push({ name: '/users/[userId]', params: { userId: '123' } })7980// Go back81router.back()8283// Go forward84router.forward()8586// Navigation guards87router.beforeEach((to, from) => {88// Guard logic89})90```9192### useRoute()9394```ts95// Generic route96const route = useRoute()9798// Typed route (preferred)99const route = useRoute('/users/[userId]')100101// Access params102const userId = route.params.userId103104// Access query105const tab = route.query.tab106107// Access meta108const requiresAuth = route.meta.requiresAuth109```110111## Data Fetching112113### useFetch()114115```ts116// Basic fetch117const { data, error, pending, refresh } = await useFetch('/api/users')118119// With params120const { data } = await useFetch('/api/users', {121query: { page: 1, limit: 10 }122})123124// With key for deduplication125const { data } = await useFetch(`/api/users/${userId}`, {126key: `user-${userId}`127})128129// Lazy fetch (doesn't block navigation)130const { data } = await useLazyFetch('/api/users')131132// Watch and refetch133const page = ref(1)134const { data } = await useFetch('/api/users', {135query: { page },136watch: [page]137})138139// Cancel requests with AbortController signal (Nuxt 4.2+)140const controller = new AbortController()141const { data } = await useFetch('/api/users', {142signal: controller.signal143})144// Later: controller.abort() to cancel the request145146// Manual cancellation via execute/refresh147const { data, execute } = await useFetch('/api/users', { immediate: false })148const abortController = new AbortController()149await execute({ signal: abortController.signal })150// Later: abortController.abort() to cancel151```152153### useAsyncData()154155```ts156// Custom async logic157const { data, error, pending, refresh } = await useAsyncData('users', async () => {158const response = await $fetch('/api/users')159return response.filter(u => u.active)160})161162// Lazy version163const { data } = await useLazyAsyncData('users', async () => {164return await $fetch('/api/users')165})166167// Cancel with AbortController (Nuxt 4.2+)168const controller = new AbortController()169const { data } = await useAsyncData('users', async () => {170return await $fetch('/api/users', { signal: controller.signal })171})172// Later: controller.abort() to cancel173174// Custom cache logic with getCachedData175const { data } = await useAsyncData('users',176async () => $fetch('/api/users'),177{178getCachedData: (key) => {179// Return cached data or null/undefined to trigger fetch180const cached = useNuxtData(key)181return cached.data.value182}183}184)185186// Deep reactivity for nested objects187// Default is shallow in Nuxt 4 (was deep in Nuxt 3)188const { data } = await useAsyncData('user',189async () => $fetch('/api/user'),190{191deep: true // Makes nested properties reactive192}193)194195// Deduplication strategies (Nuxt 4.2+)196const { data } = await useAsyncData('users',197async () => $fetch('/api/users'),198{199dedupe: 'cancel' // Cancel existing requests when new one starts200// dedupe: 'defer' // Prevent new requests while one is pending201}202)203204// Manual cancellation via execute/refresh205const { data, execute } = await useAsyncData('users',206async ({ signal }) => $fetch('/api/users', { signal }),207{ immediate: false }208)209const abortController = new AbortController()210await execute({ signal: abortController.signal })211// Later: abortController.abort() to cancel212```213214## State Management215216### useState()217218```ts219// Create shared state220const counter = useState('counter', () => 0)221222// Use in components223counter.value++224225// With type226const user = useState<User | null>('user', () => null)227```228229## App Context230231### useNuxtApp()232233```ts234const nuxtApp = useNuxtApp()235236// Access provided values237const { $api, $hello } = nuxtApp238239// Access hooks240nuxtApp.hook('page:finish', () => {241console.log('Page loaded')242})243244// Access Vue app245nuxtApp.vueApp.use(SomePlugin)246```247248### useRuntimeConfig()249250```ts251// Access runtime config252const config = useRuntimeConfig()253254// Public config (client + server)255const apiBase = config.public.apiBase256257// Private config (server only)258const apiSecret = config.apiSecret // undefined on client259```260261## Head Management262263### useHead()264265```ts266// Set page meta267useHead({268title: 'User Profile',269meta: [270{ name: 'description', content: 'View user profile' },271{ property: 'og:title', content: 'User Profile' }272],273link: [274{ rel: 'canonical', href: 'https://example.com/profile' }275]276})277278// Dynamic values279const user = ref({ name: 'John' })280useHead({281title: () => `${user.value.name}'s Profile`282})283```284285### useSeoMeta()286287```ts288// Cleaner SEO meta289useSeoMeta({290title: 'User Profile',291description: 'View user profile',292ogTitle: 'User Profile',293ogDescription: 'View user profile',294ogImage: 'https://example.com/image.jpg',295twitterCard: 'summary_large_image'296})297```298299## Best Practices300301- **Use useRequestURL()** NOT window.origin/location302- **Type routes** with useRoute('/path/[param]')303- **Use useFetch** for API calls (deduplication, SSR)304- **Key your fetches** for proper caching305- **useState for shared state** across components306- **useSeoMeta** for cleaner SEO tags307308## Common Mistakes309310| ❌ Wrong | ✅ Right |311| ---------------------------- | ----------------------------------------------------- |312| `window.origin` | `useRequestURL().origin` |313| `window.location.pathname` | `useRequestURL().pathname` |314| `fetch()` in components | `useFetch()` or `useAsyncData()` |315| `router.push('/path/' + id)` | `router.push({ name: '/path/[id]', params: { id } })` |316| Duplicate fetches | Use `key` parameter |317318## Resources319320- Nuxt composables: https://nuxt.com/docs/api/composables/use-fetch321- Data fetching: https://nuxt.com/docs/getting-started/data-fetching322- useRequestURL: https://nuxt.com/docs/api/composables/use-request-url323- **For NuxtTime, NuxtLink, NuxtImg:** See nuxt-components.md324