---
title: "OpenAPI Generation"
description: "OpenAPI Generation provides a sophisticated pipeline to transform OpenAPI specification documents into interactive, structured documentation pages. At its core, the system acts as a specialized bui..."
last_updated: "2026-07-02T09:46:39.292129+00:00"
canonical_url: "https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/api-documentation/openapi-generation"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/openapi/src/ui/operation/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/operation/index.tsx)
- [packages/openapi/src/types/openapi.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/types/openapi.ts)
- [packages/api-docs/src/components/schema/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/components/schema/index.tsx)
- [packages/api-docs/src/components/schema/client.tsx](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/components/schema/client.tsx)
- [packages/openapi/src/server/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/server/index.tsx)
- [packages/openapi/src/utils/pages/preset-auto.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/pages/preset-auto.ts)
- [packages/api-docs/src/schema/dereference.ts](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/schema/dereference.ts)
- [packages/openapi/src/utils/pages/builder.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/pages/builder.ts)
- [packages/openapi/src/generate-file.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/generate-file.ts)
- [packages/asyncapi/src/generate-file.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/generate-file.ts)
- [packages/openapi/src/utils/document/dereference.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/document/dereference.ts)
- [packages/asyncapi/src/server/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/server/index.tsx)
- [packages/openapi/tsdown.config.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/tsdown.config.ts)
- [packages/openapi/src/ui/base.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/base.tsx)
- [packages/openapi/src/utils/pages/to-static-data.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/pages/to-static-data.ts)
- [packages/openapi/src/ui/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/index.tsx)
- [packages/asyncapi/src/ui/index.tsx](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/ui/index.tsx)
- [packages/openapi/src/utils/document/load.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/document/load.ts)
- [packages/asyncapi/src/utils/document/dereference.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/utils/document/dereference.ts)
- [packages/api-docs/src/schema/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/schema/index.ts)
- [packages/openapi/src/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/index.ts)
- [packages/asyncapi/src/utils/pages/to-static-data.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/utils/pages/to-static-data.ts)
- [packages/openapi/src/types.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/types.ts)
- [packages/openapi/package.json](https://github.com/blade47/fumadocs/blob/main/packages/openapi/package.json)
- [packages/asyncapi/src/utils/pages/builder.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/utils/pages/builder.ts)
- [packages/api-docs/src/schema/bundle.ts](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/schema/bundle.ts)
- [packages/asyncapi/src/utils/schema.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/utils/schema.ts)
- [packages/asyncapi/src/utils/document/load.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/utils/document/load.ts)
- [packages/openapi/src/requests/generators/all.ts](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/requests/generators/all.ts)
- [packages/asyncapi/src/index.ts](https://github.com/blade47/fumadocs/blob/main/packages/asyncapi/src/index.ts)
</details>

OpenAPI Generation provides a sophisticated pipeline to transform OpenAPI specification documents into interactive, structured documentation pages. At its core, the system acts as a specialized build-time processor and runtime UI framework that bridges the gap between raw API schemas and developer-friendly documentation. By automating the parsing, dereferencing, and file-system generation, it ensures documentation remains tightly coupled with source specifications, eliminating the manual overhead typically associated with API documentation maintenance.

The subsystem follows a multi-stage architecture. Initially, it ingests input documents (URLs, local paths, or objects), validates them, and bundles references using `json-schema-ref-parser`. Once bundled, the system provides both a static generation path for pre-rendered site building and a dynamic runtime path for modern web framework integrations. This design ensures that the same parsing logic, type resolution, and UI component rendering are consistent regardless of whether the docs are built for static hosting or served dynamically.

A significant architectural feature is the clear separation between core specification handling and UI rendering. The generation logic treats the OpenAPI document as a graph of nodes, which are then traversed to build virtual files representing API endpoints or tags. This graph-based approach enables the system to support complex configuration (like automatic grouping by tags or routes) while maintaining a strict, predictable data structure that downstream UI components can safely consume without needing to re-parse the raw specification.

## Core Document Processing and Bundling

The lifecycle begins with the document loader, which handles the transition from raw input to a normalized internal format. Because specifications often contain complex cross-file references, the `loadDocument` function acts as the primary gatekeeper.

The mechanism performs the following sequence:
1.  **Bundling:** Uses `bundle<Document>(input)` to resolve all external `$ref` pointers into a single coherent document tree.
2.  **Upgrading:** Pipes the resulting document through `@scalar/openapi-upgrader` to ensure version compatibility (upgrading to `3.2`), normalizing the schema structure.
3.  **Caching:** The `createOpenAPI` server uses a `Map` to cache these promises, preventing redundant I/O operations if the system re-requests the same schema identifier during the build.

> [!IMPORTANT]
> The `loadDocument` utility is the only point where the raw specification enters the system. It guarantees that any document reaching the generation phase is already unified and compliant with the internal version 3.2 schema expectations.

Sources: [packages/openapi/src/utils/document/load.ts:8-20](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/document/load.ts#L8-L20)

## Schema Dereferencing and Inlining

Once a document is loaded, its components must be dereferenced for the UI to represent data structures accurately. The core mechanism resides in the `dereferenceSync` function.

The mechanism follows a recursive traversal:
1.  **Cloning:** It first uses `structuredClone` to create a working copy, isolating mutations.
2.  **Pointer Traversal:** It walks the schema object graph, maintaining a `visitedNodes` set to prevent infinite cycles.
3.  **Inlining:** When it encounters a `$ref` object, it resolves the pointer against the root schema and merges the resolved object into the current location, replacing the `$ref` entirely unless a `preserveRef` check permits keeping the pointer (useful for specific schema viewers).
4.  **Reference Mapping:** The `setOriginalRef` callback enables the UI to map resolved nodes back to their original reference paths, which is critical for generating valid "go-to-definition" UI behaviors.

Sources: [packages/api-docs/src/schema/dereference.ts:19-65](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/schema/dereference.ts#L19-L65)

## Virtual File Generation Logic

The `fromSchema` factory function is the heart of the site generation subsystem. It converts an OpenAPI spec into a list of `OutputEntry` objects that are later rendered as MDX files.

The logic proceeds via a `PagesBuilder` object that encapsulates the schema and provides accessors for operations, webhooks, and tags:
1.  **Extraction:** The `extract()` method iterates over `paths` and `webhooks`, identifying every valid method (e.g., GET, POST) and creating an `OperationItem` for each.
2.  **Grouping:** The `preset-auto` logic, specifically the `group()` function, takes these items and applies grouping logic defined in the `SchemaToPagesOptions`.
3.  **Path Mapping:** The `routePathToFilePath` method converts RESTful URL patterns (e.g., `{id}`) into filesystem-friendly paths, ensuring predictable URLs for the resulting documentation pages.

> [!NOTE]
> During grouping, entries are sorted and collected into `OutputGroup` structures before being pushed to the final file manifest. This ensures that parent `meta.json` files are correctly generated to represent the structure of the API documentation tree.

Sources: [packages/openapi/src/utils/pages/builder.ts:121-231](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/pages/builder.ts#L121-L231), [packages/openapi/src/utils/pages/preset-auto.ts:150-260](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/utils/pages/preset-auto.ts#L150-L260)

## UI Component Composition

The visual documentation is rendered by the `Operation` component, which acts as a layout container for specific API details.

The rendering pipeline is highly flexible:
1.  **Slotting:** The component defines slots for `header`, `description`, `authSchemes`, `parameters`, `body`, and `responses`.
2.  **Injection:** The actual layout is dictated by `renderOperationLayout` provided via `RenderContext`. This pattern allows users to swap the order of UI blocks without modifying the underlying component code.
3.  **State Management:** An `OperationProvider` is wrapped around the content to manage state like example ID selection (e.g., `x-exclusiveCodeSample`).

```typescript
// Example: The internal layout slotting
let content = renderOperationLayout(
  {
    header: headNode,
    description: descriptionNode,
    authSchemes: authNode,
    body: bodyNode,
    callbacks: callbacksNode,
    parameters: parameterNode,
    responses: responseNode,
    apiPlayground,
    apiExample: <UsageTabs method={method} operation={operation} pathItem={pathItem} />,
  },
  { operation, method, pathItem, ctx },
);
```
Sources: [packages/openapi/src/ui/operation/index.tsx:318-389](https://github.com/blade47/fumadocs/blob/main/packages/openapi/src/ui/operation/index.tsx#L318-L389)

## Schema Tree Visualization

The `SchemaUI` component generates an interactive tree representation of JSON schemas. It uses a recursive approach to handle object properties, arrays, and union types (`oneOf`, `anyOf`, `allOf`).

Key design decisions in `generateSchemaUI`:
- **Caching:** The function maintains an `autoIds` `WeakMap` to ensure that identical schema objects receive stable, predictable IDs across different rendering passes.
- **Filtering:** The `isVisible` guard handles field-level visibility based on the `readOnly` or `writeOnly` flags, allowing the UI to omit fields that are not relevant to the current request/response context.

| Type | Handling Mechanism | Key Logic Path |
| :--- | :--- | :--- |
| Object | Maps properties to an array of props | `out.props.push({...})` |
| Array | Resolves items schema via `getSchemaId` | `scanRefs($type, items)` |
| Union | Collapses types into a selectable toggle | `out.items.push({...})` |
| Primitive | Renders alias and info tags | `...base(schema)` |

Sources: [packages/api-docs/src/components/schema/index.tsx:114-414](https://github.com/blade47/fumadocs/blob/main/packages/api-docs/src/components/schema/index.tsx#L114-L414)

## Development and Build Lifecycle

The system utilizes `tsdown` for bundling with an `onSuccess` hook that triggers CSS generation. The CSS system uses a `Scanner` from `@tailwindcss/oxide` to crawl the UI components and extract styles.

> [!CAUTION]
> The `onSuccess` hook is critical for build-time asset generation. Manual changes to the generated CSS files inside `css/generated/` will be overwritten in the next build cycle.

Sources: [packages/openapi/tsdown.config.ts:7-77](https://github.com/blade47/fumadocs/blob/main/packages/openapi/tsdown.config.ts#L7-L77)

## Related

- [API Schema Processing](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/api-documentation/api-schema-processing)
- [Code Generation](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/api-documentation/code-generation)
- [API UI](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/technical/api-documentation/api-ui)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e8872a72-1909-479c-b585-dc74c6e26726/llms.txt) for all pages in this wiki.
