Data Fetching

    👉

    useFetch, useLazyFetch, useAsyncData and useLazyAsyncData only work during setup or Lifecycle Hooks

    Within your pages, components and plugins you can use useAsyncData to get access to data that resolves asynchronously.

    👉

    Read more in API > Composables > Use Async Data.

    server/api/count.ts

    app.vue

    1. <script setup>
    2. const { data } = await useAsyncData('count', () => $fetch('/api/count'))
    3. </script>
    4. <template>
    5. Page visits: {{ data }}
    6. </template>

    🔎

    Read and edit a live example in

    This composable behaves identically to useAsyncData with the lazy: true option set. In other words, the async function does not block navigation. That means you will need to handle the situation where the data is null (or whatever value you have provided in a custom default factory function).

    👉

    Read more in API > Composables > Use Lazy Async Data.

    Example

    1. <template>
    2. <div>
    3. {{ pending ? 'Loading' : count }}
    4. </div>
    5. </template>
    6. <script setup>
    7. const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
    8. watch(count, (newCount) => {
    9. // Because count starts out null, you won't have access
    10. })
    11. </script>

    useFetch

    Within your pages, components and plugins you can use useFetch to universally fetch from any URL.

    This composable provides a convenient wrapper around useAsyncData and $fetch. It automatically generates a key based on URL and fetch options, as well as infers API response type.

    👉

    app.vue

    1. <script setup>
    2. const { data } = await useFetch('/api/count')
    3. </script>
    4. <template>
    5. Page visits: {{ data.count }}
    6. </template>

    🔎

    Read and edit a live example in

    This composable behaves identically to useFetch with the lazy: true option set. In other words, the async function does not block navigation. That means you will need to handle the situation where the data is (or whatever value you have provided in a custom default factory function).

    👉

    Read more in API > Composables > Use Lazy Fetch.

    Example

    Refreshing Data

    Sometimes throughout the course of your user’s page visit, you may need to refresh the data loaded from the API. This can happen if the user chooses to paginate, filter results, search, etc.

    You can make use of the refresh() method returned from the useAsyncData() composable to refresh the data with different query parameters:

    1. <script setup>
    2. const page = ref(1);
    3. const { data:users, loading, refresh, error } = await useFetch(() => `users?page=${page.value}&take=6`, { baseURL: config.API_BASE_URL }
    4. );
    5. function previous(){
    6. page.value--;
    7. refresh();
    8. }
    9. function next() {
    10. page.value++;
    11. refresh();
    12. }
    13. </script>

    The key to making this work is to call the refresh() method returned from the useFetch() composable when a query parameter has changed.

    Invalidate the cache of useAsyncData, useLazyAsyncData, useFetch and useLazyFetch and trigger the refetch.

    This method is useful if you want to refresh all the data fetching for a current page.

    👉

    Read more in .

    1. <template>
    2. <div>
    3. {{ pending ? 'Loading' : count }}
    4. </div>
    5. <button @click="refresh">Refresh</button>
    6. </template>
    7. <script setup>
    8. const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
    9. const refresh = () => refreshNuxtData('count')
    10. </script>

    When we call fetch in the browser, user headers like cookie will be directly sent to the API. But during server-side-rendering, since the fetch request takes place ‘internally’ within the server, it doesn’t include the user’s browser cookies, nor does it pass on cookies from the fetch response.

    👉

    We can use useRequestHeaders to access and proxy cookies to the API from server-side.

    The example below adds the request headers to an isomorphic fetch call to ensure that the API endpoint has access to the same cookie header originally sent by the user.

    1. <script setup>
    2. const { data } = useFetch('/api/me', {
    3. headers: useRequestHeaders(['cookie'])
    4. })

    Be very careful before proxying headers to an external API and just include headers that you need.
    Not all headers are safe to be bypassed and might introduce unwanted behavior.
    Here is a list of common headers that are NOT to be proxied:

    • host, accept
    • content-length, content-md5, content-type
    • x-forwarded-host, x-forwarded-port, x-forwarded-proto
    • cf-connecting-ip, cf-ray

    Example: Pass on cookies from server-side API calls on SSR response

    If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.

    composables/fetch.ts

    1. <script setup lang="ts">
    2. // This composable will automatically pass on a cookie of our choice.
    3. const result = await fetchWithCookie("/api/with-cookie", "test")
    4. onMounted(() => console.log(document.cookie))
    5. </script>

    The data returned by these composables will be stored inside the page payload. This means that every key returned that is not used in your component will be added to the payload.

    👉

    We strongly recommend you only select the keys that you will use in your component.

    Imagine that /api/mountains/everest returns the following object:

    1. {
    2. "title": "Mount Everest",
    3. "description": "Mount Everest is Earth's highest mountain above sea level, located in the Mahalangur Himal sub-range of the Himalayas. The China–Nepal border runs across its summit point",
    4. "height": "8,848 m",
    5. "countries": [
    6. "China",
    7. "Nepal"
    8. ],
    9. "continent": "Asia",
    10. "image": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Everest_kalapatthar.jpg/600px-Everest_kalapatthar.jpg"
    11. }

    If you plan to only use title and description in your component, you can select the keys by chaining the result of $fetch or pick option:

    1. <script setup>
    2. const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] })
    3. </script>
    4. <template>
    5. <h1>{{ mountain.title }}</h1>
    6. <p>{{ mountain.description }}</p>

    Using async setup

    If you are using async setup(), the current component instance will be lost after the first await. (This is a Vue 3 limitation.) If you want to use multiple async operations, such as multiple calls to useFetch, you will need to use <script setup> or await them together at the end of setup.

    👉

    Using <script setup> is recommended, as it removes the limitation of using top-level await.

    There are instances where you may need to directly call the API. Nuxt 3 provides a globally available $fetch method using unjs/ohmyfetch (in addition to fetch) with the same API as the .

    Using has a number of benefits, including:

    Plus, it comes with convenience features including automatically parsing responses and stringifying data.