Using Nuxt 3's useFetch composable for data fetching
Learn how to use Nuxt 3's useFetch to fetch data with automatic SSR, hydration and deduplication, and avoid common pitfalls.
13 May 2026, 04:45 UTC

What useFetch does
The "useFetch" composable in Nuxt 3 provides a unified way to request data that works on both the server and the client. It returns reactive refs for "data", "pending" and "error", automatically deduplicates identical requests, and hydrates the fetched payload into the page’s initial state when SSR is enabled.
Example configuration
Create a page file "pages/index.vue" and use "useFetch" inside the "setup" function (or "script setup").
<template>
<div>
<p v-if="pending">Loading…</p>
<p v-else-if="error">Error: {{ error.message }}</p>
<ul v-else>
<li v-for="post in data" :key="post.id">
{{ post.title }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
// The await is required because useFetch returns a promise that resolves to the refs object
const { data, pending, error } = await useFetch('https://jsonplaceholder.typicode.com/posts')
</script>
The "await" unwraps the promise returned by "useFetch" and gives you the reactive refs directly. The fetched JSON becomes part of the "__NUXT__" payload when the page is rendered on the server.
How it works
- During server‑side rendering, Nuxt calls the fetch function, waits for the response, and injects the result into the HTML as a JSON string inside
"window.__NUXT__". - On the client, the same composable reads that injected state, skips a new network request, and makes the data available as a ref.
- If another component on the same page calls
"useFetch"with the same URL (or the same explicit"key"), Nuxt deduplicates the call and shares the same refs. - When
"ssr: false"is set, the composable behaves like a client‑only fetch; you must enable the"hydrate"option or use"useAsyncData"to get SSR‑like behavior.
Limits and common mistakes
- Only in Nuxt 3:
"useFetch"is not available in Nuxt 2; upgrade or use"fetch"/"asyncData"there. - Missing
"await": Forgetting to await leaves you with a promise instead of the refs, causing the template to receive an unresolved value. - Not returning the object: In
"setup"you must return the refs (or use"script setup"which exposes them automatically). - Mutating data: The
"data"ref is read‑only; direct assignment breaks Nuxt’s reactivity and can lead to stale UI. - Missing key: If you rely only on the URL for deduplication, changing query parameters without updating the URL can cause duplicate requests. Provide an explicit
"key"when needed. - Unhandled errors: Ignoring the
"error"ref can let a promise rejection halt rendering in SSR. Always check"error"or wrap the call in a"try/catch".
How to verify the behavior
- Run
"nuxt dev"in your project directory. - Open the browser’s DevTools → Network tab and reload the page. You should see a single request to the API endpoint even if you have two identical
"useFetch"calls on the page. - Right‑click the page → View page source. Search for
"__NUXT__"; you will find a JSON block containing the fetched posts. - Build for production with
"nuxt build", then start the server ("node .output/server/index.js"). Navigate to the page and confirm that the HTML already contains the data and that client‑side navigation only refetches when you change the"key"or URL.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.