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.
Create a new file in server/api/hello.ts
:
export default defineEventHandler((event) => { return { api: 'works' }})
You can now universally call this API using await $fetch('/api/hello')
.
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:
export default defineEventHandler(() => 'Hello World!')
Given the example above, the /hello
route will be accessible at http://localhost:3000/hello.
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 or check headers, log requests, or extend the event's request object.
Examples:
export default defineEventHandler((event) => { console.log('New request: ' + event.req.url)})
export default defineEventHandler((event) => { event.context.auth = { user: 123 }})
Nuxt will automatically read any files in the ~/server/plugins
directory and register them as Nitro plugins. This allows extending Nitro's runtime behavior and hooking into lifecycle events.
Example:
export default defineNitroPlugin((nitroApp) => { console.log('Nitro plugin', nitroApp)})
Server routes are powered by unjs/h3 which comes with a handy set of helpers.
You can add more helpers yourself inside the ~/server/utils
directory.
Server routes can use dynamic parameters within brackets in the file name like /api/hello/[name].ts
and be accessed via event.context.params
.
Example:
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!
.
Handle file names can be suffixed with .get
, .post
, .put
, .delete
, ... to match request's HTTP Method.
export default defineEventHandler(() => 'Test get handler')
export default defineEventHandler(() => 'Test post handler')
Given the example above, fetching /test
with:
Test get handler
Test post handler
Catch-all routes are helpful for fallback route handling. For example, creating a file named ~/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:
export default defineEventHandler(() => `Default foo handler`)
export default defineEventHandler(() => `Default api handler`)
export default defineEventHandler(async (event) => { const body = await useBody(event) return { body }})
You can now universally call this API using $fetch('/api/submit', { method: 'post', body: { test: 123 } })
.
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.Sample query /api/query?param1=a¶m2=b
export default defineEventHandler((event) => { const query = getQuery(event) return { a: query.param1, b: query.param2 }})
export default defineEventHandler((event) => { const config = useRuntimeConfig() return { key: config.KEY }})
export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies }})
You can use nitro
key in nuxt.config
to directly set Nitro configuration.
export default defineNuxtConfig({ // https://nitro.unjs.io/config nitro: {}})
import { createRouter } from 'h3'const router = createRouter()router.get('/', () => 'Hello World')export default router
Note: This is an experimental feature and is only available within Node.js environments.
import fs from 'node:fs'import { sendStream } from 'h3'export default defineEventHandler((event) => { return sendStream(event, fs.createReadStream('/path/to/file'))})
export default (req, res) => { res.end('Legacy handler')}
export default (req, res, next) => { console.log('Legacy middleware') next()}
next()
callback with a legacy middleware that is async
or returns a Promise
!Nitro provides a cross-platform storage layer. In order to configure additional storage mount points, you can use nitro.storage
.
export default defineNuxtConfig({ nitro: { storage: { 'redis': { driver: 'redis', /* redis connector options */ port: 6379, // Redis port host: "127.0.0.1", // Redis host username: "", // needs Redis >= 6 password: "", db: 0 // Defaults to 0 } } }})
Create a new file in server/api/test.post.ts
:
export default defineEventHandler(async (event) => { const body = await useBody(event) await useStorage().setItem('redis:test', body) return 'Data is set'})
Create a new file in server/api/test.get.ts
:
export default defineEventHandler(async (event) => { const data = await useStorage().getItem('redis:test') return data})
Create a new file in app.vue
:
<template> <div> <div>Post state: {{ resDataSuccess }}</div> <div>Get Data: {{ resData.text }}</div> </div></template><script setup lang="ts"> const { data: resDataSuccess } = await useFetch('/api/test', { method: 'post', body: { text: 'Nuxt is Awesome!' } }) const { data: resData } = await useFetch('/api/test')</script>