# OpenAPI

> Nitro can automatically generate an OpenAPI specification from your route handlers and serve interactive API documentation.

Nitro scans all route handlers, extracts metadata defined with `defineRouteMeta`, and generates an [OpenAPI 3.1.0](https://spec.openapis.org/oas/v3.1.0) specification. Built-in UIs powered by [Scalar](https://scalar.com/) and [Swagger UI](https://swagger.io/tools/swagger-ui/) let you explore and test your API directly in the browser.

<important>

OpenAPI support is currently experimental.

</important>

## Enable OpenAPI

Enable OpenAPI in your Nitro configuration:

<code-group>

```ts [nitro.config.ts]
import { defineConfig } from "nitro";

export default defineConfig({
  experimental: {
    openAPI: true,
  },
});
```

</code-group>

Once enabled, the following endpoints become available during development:

<table>
<thead>
  <tr>
    <th>
      Endpoint
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        /_openapi.json
      </code>
    </td>
    
    <td>
      OpenAPI 3.1.0 JSON specification
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        /_scalar
      </code>
    </td>
    
    <td>
      Scalar API reference UI
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        /_swagger
      </code>
    </td>
    
    <td>
      Swagger UI
    </td>
  </tr>
</tbody>
</table>

## 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](https://spec.openapis.org/oas/v3.1.0#operation-object).

```ts [routes/api/hello.ts]
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!" };
});
```

<note>

`defineRouteMeta` is a build-time macro. The metadata is statically extracted during the build and does not add any runtime overhead to your handlers.

</note>

### Parameters

Route parameters (`:id`, `[id]`) are automatically converted to OpenAPI path parameters. You can define additional query or header parameters in the `parameters` array:

```ts [routes/api/users/[id].get.ts]
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:

```ts [routes/api/status.ts]
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.

```ts [routes/api/users.get.ts]
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:

<table>
<thead>
  <tr>
    <th>
      Route prefix
    </th>
    
    <th>
      Tag
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        /api/
      </code>
    </td>
    
    <td>
      API Routes
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        /_
      </code>
    </td>
    
    <td>
      Internal
    </td>
  </tr>
  
  <tr>
    <td>
      Other
    </td>
    
    <td>
      App Routes
    </td>
  </tr>
</tbody>
</table>

You can override this by specifying `tags` in the `openAPI` metadata.

## Configuration

Configure OpenAPI behavior with the top-level `openAPI` option:

```ts [nitro.config.ts]
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:

<table>
<thead>
  <tr>
    <th>
      Property
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        title
      </code>
    </td>
    
    <td>
      <code>
        "Nitro Server Routes"
      </code>
    </td>
    
    <td>
      API title
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      API description
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        version
      </code>
    </td>
    
    <td>
      <code>
        "1.0.0"
      </code>
    </td>
    
    <td>
      API version
    </td>
  </tr>
</tbody>
</table>

### `route`

- Default: `"/_openapi.json"`

Override the path where the OpenAPI JSON specification is served:

```ts [nitro.config.ts]
export default defineConfig({
  openAPI: {
    route: "/_docs/openapi.json",
  },
});
```

### `ui`

Configure or disable the built-in API documentation UIs:

```ts [nitro.config.ts]
export default defineConfig({
  openAPI: {
    ui: {
      scalar: {
        route: "/_docs/scalar",
        theme: "purple",
      },
      swagger: {
        route: "/_docs/swagger",
      },
    },
  },
});
```

Set either UI to `false` to disable it:

```ts [nitro.config.ts]
export default defineConfig({
  openAPI: {
    ui: {
      swagger: false,
    },
  },
});
```

<read-more title="Scalar Configuration" to="https://github.com/scalar/scalar">



</read-more>

## Production

By default, OpenAPI endpoints are only available during development. To enable them in production, set the `production` option:

```ts [nitro.config.ts]
export default defineConfig({
  openAPI: {
    production: "runtime",
  },
});
```

<table>
<thead>
  <tr>
    <th>
      Value
    </th>
    
    <th>
      Behavior
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code className="language-ts shiki shiki-themes github-light github-dark github-dark" language="ts" style="">
        <span class="suiK_">
          false
        </span>
      </code>
    </td>
    
    <td>
      Disabled in production (default)
    </td>
  </tr>
  
  <tr>
    <td>
      <code className="language-ts shiki shiki-themes github-light github-dark github-dark" language="ts" style="">
        <span class="sfrk1">
          "runtime"
        </span>
      </code>
    </td>
    
    <td>
      Specification is generated at runtime on each request
    </td>
  </tr>
  
  <tr>
    <td>
      <code className="language-ts shiki shiki-themes github-light github-dark github-dark" language="ts" style="">
        <span class="sfrk1">
          "prerender"
        </span>
      </code>
    </td>
    
    <td>
      Specification is generated at build time and served as a static file
    </td>
  </tr>
</tbody>
</table>

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.

<warning>

If you enable OpenAPI in production, make sure to protect the endpoints with appropriate authentication or access control.

</warning>
