useFetch()

SSR-friendly composable that fetches data and caches it with a unique key.

Since Nuxt 3.0 Spec ↗

Syntax

const { data, error, status, refresh, pending } = await useFetch(url, options)

Parameters

NameTypeRequiredDescription
url string | Request | Ref | (() => string) Yes The request URL. Can be a reactive ref or a function for dynamic requests that re-run when dependencies change.
options object No Options including `method`, `query`, `body`, `headers`, `key`, `server`, `lazy`, `default`, `transform`, `pick`, `watch`, and `immediate`. Also accepts all `$fetch` (ofetch) options.

Returns

AsyncData<DataT, ErrorT> — Reactive refs: data, error, status, pending, refresh, execute, clear.

Examples

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

<template>
  <p v-if="error">Failed to load</p>
  <ul v-else>
    <li v-for="p in posts" :key="p.id">{{ p.title }}</li>
  </ul>
</template>
<script setup lang="ts">
const id = useRoute().params.id
// Reactive key + transform/pick to reduce payload size
const { data } = await useFetch(`/api/users/${id}`, {
  key: `user-${id}`,
  pick: ['name', 'email'],
})
</script>
<script setup lang="ts">
const search = ref('')
// Function URL re-runs whenever `search` changes
const { data } = await useFetch(() => `/api/search?q=${search.value}`, {
  watch: [search],
})
</script>

Notes

`useFetch` runs on the server during SSR and the result is serialized into the payload so it is not re-fetched during client hydration. It must be called in a Nuxt context (setup, plugin, or route middleware). A key is auto-generated from the file/line and URL; pass an explicit `key` when the URL is dynamic to avoid mismatches. It is a thin wrapper around `useAsyncData` + `$fetch`. Use `useLazyFetch` to avoid blocking navigation.

See also