Typed API Routes

useFetch Infers Your Server Route Types

Typed API Routes

When you call useFetch with an internal /api/... path, Nuxt infers the response type from the server handler's return type — no manual generics needed.

4 min read Level 2/5 #nuxt#server#types
What you'll learn
  • Annotate handler return types so Nuxt can infer them
  • See useFetch pick up the inferred types on the client
  • Cast manually with a generic parameter when inference falls short

One of Nuxt’s secret superpowers: when your useFetch URL points at an internal route, the result type is inferred from the handler’s return annotation. End-to-end typing without any code generation.

Annotate the Handler

// server/api/users.get.ts
export interface User {
  id: string
  name: string
  email: string
}

export default defineEventHandler(async (): Promise<User[]> => {
  return [
    { id: '1', name: 'Ada', email: 'ada@example.com' },
    { id: '2', name: 'Grace', email: 'grace@example.com' },
  ]
})

Infer on the Client

<script setup lang="ts">
const { data, pending, error } = await useFetch('/api/users')
// data is Ref<User[] | null>, fully typed — no generic needed
</script>

<template>
  <ul v-if="data">
    <li v-for="u in data" :key="u.id">{{ u.name }} - {{ u.email }}</li>
  </ul>
</template>

Hover over data in your editor — it knows the response shape.

Dynamic Routes

The inferred type works for routes with bracket params too:

// server/api/users/[id].get.ts
export default defineEventHandler(async (event): Promise<User> => {
  const id = getRouterParam(event, 'id')!
  return { id, name: 'Ada', email: 'ada@example.com' }
})
const route = useRoute()
const { data } = await useFetch(() => `/api/users/${route.params.id}`)
// data: Ref<User | null>

When to Use a Generic

For external APIs, or when inference can’t follow you (conditional logic, generic helpers), pass a generic to useFetch:

interface PostsResponse {
  posts: { id: number; title: string }[]
}
const { data } = await useFetch<PostsResponse>('https://api.example.com/posts')

Tips

  • Always annotate the handler’s return type explicitly. Inferring from the function body works but is fragile — small refactors silently change the public type.
  • Export your handler interfaces from a shared types/ folder so client code can reference them for things like form input shapes.
Sharing Server Utilities →