SSR & Data Fetching — Series 3

Preview — 3 of 10 questions

Given two sibling components both calling useFetch('/api/user-profile') during the same SSR pass, does the server actually make two separate HTTP requests?

javascript
<!-- Header.vue -->
<script setup>
const { data: profile } = await useFetch('/api/user-profile')
</script>

<!-- Sidebar.vue  rendered in the same page, same SSR pass -->
<script setup>
const { data: profile } = await useFetch('/api/user-profile')
</script>
AuseFetch derives a cache key automatically from the request (URL plus options, by default) — when two calls during the same render resolve to the same key, Nuxt's payload/data layer recognizes the duplication and serves both components from a single shared underlying fetch rather than issuing the request twice. This deduplication is exactly why unrelated components can each independently call useFetch for data they need without needing to coordinate who "owns" fetching it — redundant simultaneous calls collapse into one real request
BYes — every useFetch call always triggers its own independent network request, regardless of whether an identical one is already in flight or has already completed
CThis only works if both components are rendered as children of the exact same parent component — sibling components at different points in the tree always trigger separate requests
DDeduplication only happens client-side; during SSR, every useFetch call always makes its own separate server-side request regardless of key matching

When should code reach for the raw $fetch (ofetch) function directly, rather than useFetch?

javascript
<script setup>
// Initial page data — uses useFetch
const { data: products } = await useFetch('/api/products')

// A one-off action triggered by a button click — uses $fetch directly
async function addToCart(productId) {
  await $fetch('/api/cart', { method: 'POST', body: { productId } })
}
</script>
A$fetch and useFetch are interchangeable in every context — this code could use either one for both purposes with no meaningful difference
BuseFetch should always be used, everywhere, including inside event handlers — using raw $fetch anywhere in a Nuxt app is considered a mistake
CuseFetch is specifically designed for SSR-aware page data loading — it participates in the SSR-to-client payload transfer, dedup keying, and the reactive data/pending/error refs meant to drive a page's initial render. A one-off imperative action like addToCart, triggered by a user interaction well after the page has already rendered, doesn't need any of that SSR machinery — it just needs to make a request and handle the result right there, which is exactly what calling the lighter-weight $fetch directly (the same underlying fetch utility useFetch itself uses internally) is for
D$fetch can only be called from within Nitro server routes, never from client-side component code

Why is this preferable to fetching the full response and then filtering it in the component afterward?

javascript
const { data: productNames } = await useAsyncData('product-names', () => $fetch('/api/products'), {
  transform: (products) => products.map((p) => p.name),
})
Atransform runs the fetch twice — once to get the raw data, once with the transform applied — doubling the number of network requests
Btransform has no actual effect on what's serialized into the SSR-to-client payload — the full untransformed response is always sent to the client regardless of this option
Ctransform is purely a TypeScript-level type annotation — it has no effect on the actual runtime data at all
Dtransform runs on the result of the fetch, before it's stored as data — critically, this means the SSR-to-client payload embedded in the page's HTML only needs to include the transformed, already-reduced shape (just an array of names here), not the full original response, which can meaningfully shrink the payload size for a case where a component only actually needs a small slice of a much larger API response. Filtering after the fact in the component, by contrast, would still require the full untransformed data to be fetched, stored, and shipped to the client as part of the hydration payload

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.