Cansu Arı Logo
Blog
How To Do?

useAsyncData vs useFetch vs onMounted: Where and When Should You Fetch Data?

Nuxt 3 offers three strong approaches to data fetching: useAsyncData, useFetch, and onMounted. Which one when? Let’s compare them for SSR, CSR, and performance.

  • #Nuxt 3
  • #Vue.js

Skip to content

useAsyncData vs useFetch vs onMounted

These three look similar, but they differ in timing and server–client behavior.

Here’s how to choose the right one, with SSR (Server-Side Rendering) vs CSR (Client-Side Rendering) in mind.

What makes Nuxt different?

In plain Vue, you might fetch in onMounted or a custom fetch. Nuxt, with SSR, can fetch data on the server and inline it into the initial HTML. Pages load faster and SEO improves.

In Nuxt 3, data fetching isn’t just a detail—it’s part of your render strategy.

useAsyncData

useAsyncData is SSR-friendly and runs on both server and client. It loads data before the page renders so content is ready on first paint.
<script setup>
const { data: products, pending, error } = await useAsyncData('products', () => $fetch('/api/products'))
</script>

When to use

  • When data should be ready on first load.
  • When SEO matters (blogs, e-commerce, news).
  • When you want cache across navigations.

Pros

  • Full SSR support.
  • Automatic key-based caching.
  • Built-in pending, error, refresh.
  • Readable code.

Cons

  • Usable only during setup.
  • Each await can delay render if overused.
Note: With the same key (e.g., 'products'), Nuxt returns cached data.

useFetch

useFetch is a convenience wrapper around useAsyncData that inlines $fetch.
<script setup>
const { data, pending, error } = await useFetch('/api/posts')
</script>

When to use

  • Simple GETs.
  • Static endpoints like /api/posts.
  • You still get SSR and caching.

Pros

  • One-liner data fetching.
  • Automatic JSON parsing via $fetch.
  • SSR-compatible.

Cons

  • Less flexible for complex params/transforms.
  • Slightly less control than useAsyncData.
In short: useFetch = useAsyncData + $fetch convenience.

onMounted

onMounted is classic Vue and runs client-side only—it doesn’t participate in SSR.
<script setup>
import { ref, onMounted } from 'vue'
const posts = ref([])

onMounted(async () => {
const res = await fetch('/api/posts')
posts.value = await res.json()
})
</script>

When to use

  • Data is only needed in the browser (user-specific content).
  • In non-SSR components.
  • After interactions (scroll/click) for dynamic loading.

Pros

  • Reduces SSR work.
  • Ideal for small dynamic pieces.

Cons

  • Not SEO-friendly.
  • Page may load empty and fill later (flicker).

SSR vs CSR comparison

PropertyuseAsyncDatauseFetchonMounted
RuntimeSSR + CSRSSR + CSRCSR only
SEO
Caching
Ease of useMediumEasySimple
PerformanceMost optimizedOptimizedLightest runtime cost

Real-world scenarios

Blog page:
const { data: posts } = await useAsyncData('posts', () => $fetch('/api/posts'))
SSR needed → useAsyncData

Dashboard widget:

const { data } = await useFetch('/api/stats')

Small payload, quick render → useFetch

User-specific data:

onMounted(async () => {
const profile = await fetchUser()
})

Requires token/cookies → onMounted

Advanced: lazy & parametric requests

Both useAsyncData and useFetch support lazy and server options:
const { data, refresh } = await useAsyncData('user', () => $fetch(`/api/user/${id}`), {
lazy: true,
server: false
})
  • lazy: true → don’t block initial render; fetch later.
  • server: false → skip SSR; run only on client.
These knobs give you fine control between SSR and CSR.

Conclusion

Nuxt 3 gives you three solid tools:
  • useAsyncData: SSR-first, SEO-friendly, cached.
  • useFetch: Simple and practical for straightforward requests.
  • onMounted: Client-only for user-specific or interaction-driven loads.
Quick guide:
  • Need SEO → useAsyncData
  • Simple API → useFetch
  • User/private data → onMounted
Pick wisely—your choice directly impacts performance and UX.
All tags
  • Nuxt 3
  • Vue.js