Routing
Nitro support filesystem routing as well as defining route rules for maximum flexibility and performance.
Filesystem Routing
Nitro supports file-based routing for your API routes.
Handler files inside api/
and routes/
directory will be automatically mapped to unjs/h3 routes.
api/
test.ts <-- /api/test
routes/
hello.ts <-- /hello
nitro.config.ts
api/
directory as a feature, therefore routes placed in /api
wont work.
You will have to use routes/api/
.Simple route
// api/hello.ts
export default defineEventHandler(() => {
return { hello: 'world' }
})
You can now universally call this API using await $fetch('/api/hello')
.
Route with params
// routes/hello/[name].ts
export default defineEventHandler(event => `Hello ${event.context.params.name}!`)
Hello nitro!
To include the /
, use [...name].ts
:
// routes/hello/[...name].ts
export default defineEventHandler(event => `Hello ${event.context.params.name}!`)
Hello nitro/is/hot!
Specific request method
API route with a specific HTTP request method (get, post, put, delete, options and so on).
// routes/users/[id].get.ts
export default defineEventHandler(async (event) => {
const { id } = event.context.params
// TODO: fetch user by id
return `User profile!`
})
Check out h3 JSDocs for all available utilities like readBody
.
Catch all route
// routes/[...].ts
export default defineEventHandler(event => `Default page`)
Route Rules
Nitro allows you to add logic at the top-level of your configuration, useful for redirecting, proxying, caching and adding headers to routes.
It is a map from route pattern (following unjs/radix3) to route options.
When cache
option is set, handlers matching pattern will be automatically wrapped with defineCachedEventHandler
.
See the Cache API for all available cache options.
swr: true|number
is shortcut for cache: { swr: true, maxAge: number }
Example:
export default defineNitroConfig({
routeRules: {
'/blog/**': { swr: true },
'/blog/**': { swr: 600 },
'/blog/**': { static: true },
'/blog/**': { cache: { /* cache options*/ } },
'/assets/**': { headers: { 'cache-control': 's-maxage=0' } },
'/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
'/old-page': { redirect: '/new-page' },
'/proxy/example': { proxy: 'https://example.com' },
'/proxy/**': { proxy: '/api/**' },
}
})
Route Middleware
Nitro route middleware can hook into the request lifecycle.
Middleware are auto-registered within the middleware/
directory.
routes/
hello.ts
middleware/
auth.ts
logger.ts
...
nitro.config.ts
Simple Middleware
Middleware are defined exactly like route handlers with the only exception that they should not return anything. Returning from middleware behaves like returning from a request - the value will be returned as a response and further code will not be ran.
export default defineEventHandler((event) => {
// Extends or modify the event
event.context.user = { name: 'Nitro' }
})
Execution Order
Middleware are executed in directory listing order.
middleware/
auth.ts <-- First
logger.ts <-- Second
... <-- Third
Prefix middleware with a number to control their execution order.
middleware/
1.logger.ts <-- First
2.auth.ts <-- Second
3.... <-- Third
Request Filtering
Middleware are executed on every request.
Apply custom logic to scope them to specific conditions.
For example, you can use the URL to apply a middleware to a specific route:
export default defineEventHandler((event) => {
// Will only execute for /auth route
if (getRequestURL(event).startsWith('/auth')) {
event.context.user = { name: 'Nitro' }
}
})