Documentation
Introduction
Typed APIs, generated clients, and OpenAPI for Nuxt server routes — from one endpoint definition.
Nuxt Endpoints lets you describe an HTTP endpoint once, next to its handler, with the schema library you already use — Zod, Valibot, or Effect Schema. Everything else is derived from that single definition:
- Runtime validation —
params,query,headers, andbodyare validated before your handler runs. Handler code sees parsed schema output, so coercion and transforms are already applied. - A fully typed client —
$endpointanduseEndpointare generated from your routes. Request options, success bodies, and declared error responses are all inferred. No codegen step, no types to import. - OpenAPI 3.1 — a document generated from the same schemas, served at
/_endpoints/schema. There is no separate spec to maintain, so it cannot go stale. - Progressive forms —
useEndpointFormprojects native GET and POST forms from the same contract, including no-JavaScript submissions and typed enhanced results.
Show me
One route file declares the contract and the handler:
// server/api/users/[id].get.ts
import { z } from 'zod'
export default defineEndpoint({
summary: 'Get a user',
request: {
params: z.object({ id: z.coerce.number() }),
},
responses: {
200: z.object({ id: z.number(), name: z.string() }),
404: z.object({ message: z.string() }),
},
handler: (event) => {
const { params } = event.validated
const user = findUser(params.id) // params.id is a number — validated and coerced
if (!user) return event.respond(404, { message: 'Not found' })
return user
},
})
Every component can now call it with full inference — including typed error branches:
<script setup lang="ts">
const result = await $endpoint('/api/users/:id', {
method: 'get',
params: { id: '1' },
})
if (result.status === 404) {
result.body.message // typed as the 404 schema
}
</script>
The boundary stays an explicit, file-based Nuxt HTTP route, callable by mobile
apps, other services, or curl, and documented through the generated OpenAPI
document.
Adopt at your own pace
Adding the module changes nothing by itself. Only routes that directly default-export defineEndpoint({...}) are affected; every other route keeps working exactly as before. See Incremental Adoption.
Nuxt Endpoints supports Nuxt 4.5+ today and is designed to adopt the route-contract primitives being developed for the Nuxt 5 generation. The
$endpoint/useEndpointUX remains the stable boundary while lower-level implementation moves upstream. See Compatibility and follow the Nuxt 5 integration progress.
Next steps
- Getting Started — install the module and define your first endpoint.
- Nuxt 5 Progress — follow the public integration branches and current status.
- Define Endpoints — the full contract surface: request parts, multiple responses, validation options.
- Generated Client — everything
$endpointanduseEndpointcan do.
Curious how it works and why it is designed this way? Read the Mental Model and Why Nuxt Endpoints?, or see how it compares to alternatives.