OpenAPI
Nitro scans all route handlers, extracts metadata defined with defineRouteMeta, and generates an OpenAPI 3.1.0 specification. Built-in UIs powered by Scalar and Swagger UI let you explore and test your API directly in the browser.
Enable OpenAPI
Enable OpenAPI in your Nitro configuration:
import { defineConfig } from "nitro";
export default defineConfig({
experimental: {
openAPI: true,
},
});
Once enabled, the following endpoints become available during development:
| Endpoint | Description |
|---|---|
/_openapi.json | OpenAPI 3.1.0 JSON specification |
/_scalar | Scalar API reference UI |
/_swagger | Swagger UI |
Route Metadata
Use the defineRouteMeta macro in route handler files to provide OpenAPI metadata for each route. The openAPI property accepts a standard OpenAPI Operation Object.
import { defineRouteMeta, defineHandler } from "nitro";
defineRouteMeta({
openAPI: {
tags: ["greeting"],
description: "Returns a greeting message",
responses: {
200: { description: "Successful greeting" },
},
},
});
export default defineHandler(() => {
return { message: "Hello, world!" };
});
defineRouteMeta is a build-time macro. The metadata is statically extracted during the build and does not add any runtime overhead to your handlers.Parameters
Route parameters (:id, [id]) are automatically converted to OpenAPI path parameters. You can define additional query or header parameters in the parameters array:
import { defineRouteMeta, defineHandler } from "nitro";
defineRouteMeta({
openAPI: {
tags: ["users"],
description: "Get a user by their ID",
parameters: [
{
in: "query",
name: "include",
description: "Comma-separated list of related resources to include",
schema: { type: "string" },
},
],
responses: {
200: { description: "User found" },
404: { description: "User not found" },
},
},
});
export default defineHandler((event) => {
const { id } = event.context.params;
return { id, name: "Alice" };
});
In this example, the id path parameter is automatically inferred from the route pattern. Only the additional include query parameter needs to be declared.
Response Schemas
Define response content types and schemas using the standard OpenAPI responses object:
import { defineRouteMeta, defineHandler } from "nitro";
defineRouteMeta({
openAPI: {
description: "Returns the current server status",
responses: {
200: {
description: "Server status",
content: {
"application/json": {
schema: {
type: "object",
properties: {
status: { type: "string", enum: ["healthy", "degraded"] },
uptime: { type: "number" },
},
},
},
},
},
},
},
});
export default defineHandler(() => {
return { status: "healthy", uptime: process.uptime() };
});
Global Components
Use the $global property to define reusable schemas that are hoisted to the top-level components section of the OpenAPI specification. This lets you reference shared schemas with $ref across multiple routes.
import { defineRouteMeta, defineHandler } from "nitro";
defineRouteMeta({
openAPI: {
tags: ["users"],
description: "List all users",
responses: {
200: {
description: "List of users",
content: {
"application/json": {
schema: {
type: "array",
items: { $ref: "#/components/schemas/User" },
},
},
},
},
},
$global: {
components: {
schemas: {
User: {
type: "object",
properties: {
id: { type: "string" },
name: { type: "string" },
email: { type: "string", format: "email" },
},
},
},
},
},
},
});
export default defineHandler(() => {
return [{ id: "1", name: "Alice", email: "alice@example.com" }];
});
Once defined, the User schema can be referenced from any other route with { $ref: "#/components/schemas/User" } without re-declaring it.
Automatic Tagging
Routes are automatically tagged based on their path prefix:
| Route prefix | Tag |
|---|---|
/api/ | API Routes |
/_ | Internal |
| Other | App Routes |
You can override this by specifying tags in the openAPI metadata.
Configuration
Configure OpenAPI behavior with the top-level openAPI option:
import { defineConfig } from "nitro";
export default defineConfig({
experimental: {
openAPI: true,
},
openAPI: {
meta: {
title: "My API",
description: "My awesome API",
version: "2.0.0",
},
},
});
meta
Set the API metadata that appears in the specification's info object:
| Property | Default | Description |
|---|---|---|
title | "Nitro Server Routes" | API title |
description | — | API description |
version | "1.0.0" | API version |
route
- Default:
"/_openapi.json"
Override the path where the OpenAPI JSON specification is served:
export default defineConfig({
openAPI: {
route: "/_docs/openapi.json",
},
});
ui
Configure or disable the built-in API documentation UIs:
export default defineConfig({
openAPI: {
ui: {
scalar: {
route: "/_docs/scalar",
theme: "purple",
},
swagger: {
route: "/_docs/swagger",
},
},
},
});
Set either UI to false to disable it:
export default defineConfig({
openAPI: {
ui: {
swagger: false,
},
},
});
Production
By default, OpenAPI endpoints are only available during development. To enable them in production, set the production option:
export default defineConfig({
openAPI: {
production: "runtime",
},
});
| Value | Behavior |
|---|---|
false | Disabled in production (default) |
"runtime" | Specification is generated at runtime on each request |
"prerender" | Specification is generated at build time and served as a static file |
Use "prerender" when the specification does not change between deployments for the best performance. Use "runtime" if you need dynamic server information or middleware access.