useAsyncData

When You Need Logic Beyond a Plain Fetch

useAsyncData

useAsyncData accepts a handler function — perfect for composing multiple fetches, calling non-HTTP sources, or transforming a response.

4 min read Level 3/5 #nuxt#useAsyncData
What you'll learn
  • Provide a unique key and an async handler to useAsyncData
  • Compose multiple parallel fetches inside a single handler
  • Reshape responses with the transform option

When useFetch is not flexible enough — you need to combine multiple endpoints, call a database directly, or reshape data — reach for useAsyncData.

Signature

useAsyncData(key, handler, options?)

The key must be unique per page. Nuxt uses it to dedupe and to serialize the payload from server to client.

Composing Multiple Fetches

<script setup lang="ts">
const { data } = await useAsyncData('home', async () => {
  const [posts, tags] = await Promise.all([
    $fetch('/api/posts'),
    $fetch('/api/tags')
  ])
  return { posts, tags }
})
</script>

<template>
  <h2>Posts</h2>
  <ul><li v-for="p in data?.posts" :key="p.id">{{ p.title }}</li></ul>
  <h2>Tags</h2>
  <ul><li v-for="t in data?.tags" :key="t.id">{{ t.name }}</li></ul>
</template>

Useful Options

  • transform: (raw) => shaped — reshape the result before it lands in data.
  • default: () => initialValue — start with a value instead of null.
  • pick: ['id', 'name'] — keep only listed fields (smaller payload).
  • watch: [refA, refB] — re-run when these refs change.
const { data } = await useAsyncData('posts', () => $fetch('/api/posts'), {
  transform: (r) => r.posts,
  default: () => [],
  pick: ['id', 'title']
})

When to Use It Over useFetch

If your “fetch” is anything more than GET url, prefer useAsyncData. Direct DB queries inside a server-only handler are a great fit too — just remember the result must be JSON-serializable for the payload.

useLazyFetch and lazy: true →