Nuxt 3 useAsyncData: Payload Hydration & SSR Request Deduplication
- Last updated
- Prerequisites:
- Nuxt 3 SSR fundamentals
- Vue 3 Composition API
- vue
- nuxt
- useAsyncData
- useFetch
- ssr
- hydration
- deduplication
Read at your depth
The practical view
`useAsyncData(key, handler)` is Nuxt 3's composable for fetching data during Server-Side Rendering (SSR) without duplicating the network request on client hydration. `const { data, pending, error, refresh } = await useAsyncData('users', () => $fetch('/api/users'))`. Nuxt executes the handler on the server, inlines the result into the SSR payload (`nuxtApp.payload.data[key]`), and on client hydration, reads directly from the payload cache.
The same idea in other frameworks
Next.js React Server Components passing serialized props to client boundaries.Angular SSR `TransferState` caching HTTP responses between server and client.Nuxt 3 `useAsyncData('key', () => $fetch(...))` payload hydration.SvelteKit `+page.server.ts` `load()` serializing data into page payload.Legacy vs modern
Naive onMounted Client Fetch vs Nuxt useAsyncData SSR Hydration
Fetching in `onMounted` causes layout shifts and double-fetching; `useAsyncData` renders on the server and hydrates from payload.
onMounted(async () => { users.value = await $fetch('/api/users'); }); // ❌ Fails SSR & SEOconst { data: users } = await useAsyncData('users', () => $fetch('/api/users')); // ✅ NEWInterview gotchas
Context
Interviewers test your knowledge of Nuxt's auto-generated key heuristics.
The mechanical answer
If the `key` argument is omitted (e.g. `useAsyncData(() => $fetch(...))`), Nuxt auto-generates a key based on the file path and line number of the call site. However, if you extract `useAsyncData` into a shared custom composable called from multiple components, they will share the *same* auto-generated key, causing one call to overwrite the other's payload. Always provide an explicit unique key when wrapping in custom composables.
Trap
Never use dynamic runtime IDs (e.g. `Math.random()`) as the key; keys must be deterministic between server and client for payload hydration matching.
Context
Checks knowledge of Nuxt 3 composable sugar wrappers.
The mechanical answer
`useFetch(url)` is a convenient shorthand wrapper that automatically calls `useAsyncData` under the hood. It auto-generates a cache key based on the URL and options, and automatically sets up reactive URL watchers. `useAsyncData` is the lower-level primitive useful for non-fetch async operations (e.g. querying a CMS SDK, Redis, or local database directly).
Trap
Using `$fetch` alone without `useAsyncData` inside a setup function will cause the request to execute twice: once on the server, and again on client hydration.