Server Routes

Nuxt automatically scans files inside the ~/server/api, ~/server/routes, and ~/server/middleware directories to register API and server handlers with HMR support.

Each file should export a default function defined with defineEventHandler().

The handler can directly return JSON data, a Promise or use event.res.end() to send response.

👉

Read more in Nitro Route Handling Docs.

Usage Example

Create a new file in server/api/hello.ts:

/server/api/hello.ts

  1. export default defineEventHandler((event) => {
  2. return {
  3. api: 'works'
  4. }
  5. })

You can now universally call this API using await $fetch('/api/hello').

Server Routes

Files inside the ~/server/api are automatically prefixed with /api in their route. For adding server routes without /api prefix, you can instead put them into ~/server/routes directory.

Example:

/server/routes/hello.ts

  1. export default defineEventHandler(() => 'Hello World!')

Given the Example above, the /hello route will be accessible at http://localhost:3000/hello.

Server Middleware

Nuxt will automatically read in any file in the ~/server/middleware to create server middleware for your project.

Middleware handlers will run on every request before any other server route to add check and some headers, log requests, or extend the event’s request object.

Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error.

Examples:

/server/middleware/log.ts

  1. export default defineEventHandler((event) => {
  2. console.log('New request: ' + event.req.url)
  3. })

/server/middleware/auth.ts

  1. export default defineEventHandler((event) => {
  2. event.context.auth = { user: 123 }
  3. })

Matching Route Parameters

Server routes can use dynamic parameters within brackets in the file name like /api/hello/[:name].ts and accessed via event.context.params.

Example:

/server/api/hello/[name].ts

  1. export default defineEventHandler(event => `Hello, ${event.context.params.name}!`)

You can now universally call this API using await $fetch('/api/hello/nuxt') and get Hello, nuxt!.

Matching HTTP Method

Handle file names can be suffixed with .get, .post, .put, .delete, … to match request’s HTTP Method.

/server/api/test.get.ts

  1. export default defineEventHandler(() => 'Test get handler')

/server/api/test.post.ts

  1. export default defineEventHandler(() => 'Test post handler')

Given the Example above, fetching /test with:

  • GET method: Returns Test get handler
  • POST method: Returns Test post handler
  • Any other method: Returns 404 error

Catch-all route

Catch-all routes are helpful for fallback route handling. For Example, creating a file in the ~/server/api/foo/[...].ts will register a catch-all route for all requests that do not match any route handler, such as /api/foo/bar/baz.

Examples:

/server/api/foo/[…].ts

  1. export default defineEventHandler(() => `Default foo handler`)

/server/api/[…].ts

  1. export default defineEventHandler(() => `Default api handler`)

Handling Requests with Body

/server/api/submit.post.ts

  1. export default defineEventHandler(async (event) => {
  2. const body = await useBody(event)
  3. return { body }
  4. })

You can now universally call this API using $fetch('/api/submit', { method: 'post', body: { test: 123 } }).

We are using submit.post.ts in the filename only to match requests with POST method that can accept the request body. When using useBody within a GET request, useBody will throw a 405 Method Not Allowed HTTP error.

Access Request Cookies

  1. export default defineEventHandler((event) => {
  2. const cookies = useCookies(event)
  3. return { cookies }
  4. })

Using a nested router

/server/api/hello.ts

  1. import { createRouter } from 'h3'
  2. const router = createRouter()
  3. router.get('/', () => 'Hello World')
  4. export default router

Return a legacy handler or middleware

/server/api/legacy.ts

  1. export default (req, res) => {
  2. res.end('Legacy handler')
  3. }

Legacy support is possible using unjs/h3 but it adviced to avoid legacy handlers as much as you can.

/server/middleware/legacy.ts

  1. export default (req, res, next) => {
  2. console.log('Legacy middleware')
  3. next()
  4. }

Never combine next() callback with a legacy middleware that is async or returns a Promise!

Server Utils

Server routes are powered by unjs/h3 which comes with a handy set of helpers.

👉

Read more in Available H3 Request Helpers.

You can add more helpers by yourself inside the ~/server/utils directory.