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.
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 indata.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.