Vue & Nuxt Tips
·
2 min read

Nuxt Tip: Difference Between useFetch and event.$fetch

Michael Hoffmann

Michael Hoffmann

@mokkapps

Nuxt Tip: Difference Between useFetch and event.$fetch Image

When working with Nuxt, you may encounter a situation where you need to fetch data from your own API routes on the server. In this context, you can use event.$fetch that can significantly improve performance and ensure SSR correctness compared to using useFetch or plain $fetch. Let's explore the key differences and best practices for using these tools effectively in your Nuxt applications.

The Key Difference: event.$fetch vs Plain $fetch

The crucial difference lies in what happens when you call these on the server targeting a local API route:

event.$fetch:

  • Makes an internal fetch — directly invokes the matching server handler function
  • Bypasses the network stack entirely
  • No TCP connection, no serialization overhead

Plain $fetch:

  • Makes a real outgoing HTTP request
  • Requires a network round-trip to localhost
  • Goes through the full HTTP serialization process

Example: Fetching Data in Nitro Server Routes

When composing multiple API routes or aggregating data from other internal API endpoints, always use event.$fetch():

server/api/users-with-stats.ts
export default defineEventHandler(async (event) => {
  // ✅ Recommended: Direct handler invocation
  const users = await event.$fetch('/api/users')
  const stats = await event.$fetch('/api/stats')
  
  return {
    users,
    stats,
    timestamp: new Date().toISOString()
  }
})

Antipattern: Using Plain $fetch in Server Routes

server/api/users-with-stats.ts
export default defineEventHandler(async (event) => {
  // ❌ Incorrect: Makes unnecessary HTTP requests
  const users = await $fetch('http://localhost:3000/api/users')
  const stats = await $fetch('http://localhost:3000/api/stats')
  
  return { users, stats }
})

In this antipattern, each call goes through the full HTTP stack, making the route slower and creating potential circular dependencies or network bottlenecks during server-side rendering.

Why It Matters

Performance

  • Direct invocation eliminates the TCP connection overhead and serialization costs of a localhost HTTP request
  • Significantly faster for server-side data fetching

Context Propagation

  • event.$fetch automatically forwards the original request's headers and cookies to the handler
  • Since it has direct access to the request event, context is preserved seamlessly

SSR Correctness

  • event.$fetch is the recommended way to call your own API routes server-side
  • Prevents unnecessary network round-trips during server-side rendering
  • Ensures your application doesn't duplicate work or create bottlenecks during rendering

Client-Side Usage

On the client-side, useFetch is already optimized and handles the distinction for you:

pages/users.vue
<script setup lang="ts">
// ✅ Already optimized - no need for useRequestFetch
const { data: users } = await useFetch('/api/users')
</script>

<template>
  <div>
    <div v-for="user in users" :key="user.id">
      {{ user.name }}
    </div>
  </div>
</template>

Summary

Use event.$fetch (accessed via useRequestFetch) when making API calls to your own routes on the server. This ensures optimal performance, proper context propagation, and SSR correctness by avoiding unnecessary HTTP network requests during server-side rendering.

If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more.