Skip to Content
Fumadocs

OpenAPI

Generating docs for OpenAPI schema.

Setup

Install the required packages.

npm i fumadocs-openapi shiki

Generate Styles

Add the following line:

Tailwind CSS
@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
@import 'fumadocs-openapi/css/preset.css';

Configure Plugin

Create the OpenAPI server instance and the <OpenAPIPage /> component.

import { createOpenAPI } from 'fumadocs-openapi/server';

// note: this is a server-side API
export const openapi = createOpenAPI({
  // the OpenAPI schema, you can also give it an external URL.
  input: ['./openapi.json'],
});

See createOpenAPI() and createOpenAPIPage() for their options.

Generate Pages

Pass staticSource() to your loader(). It generates pages without writing files.

lib/source.ts
import { loader } from 'fumadocs-core/source';
import { defineDocs } from 'fumadocs-mdx/macro';
import { openapi } from '@/lib/openapi'; 

const docs = defineDocs({
  dir: 'content/docs',
});

export const source = loader(
  {
    docs: docs.toFumadocsSource(),
    openapi: await openapi.staticSource({
      baseDir: 'openapi',
    }),
  },
  {
    baseUrl: '/docs',
    // optional: adds a badge to each page item in page tree
    plugins: [openapi.loaderPlugin()],
  },
);

staticSource() generates a page per operation by default. See Generating Pages to customize them.

Pages of source now have two types, docs and openapi. Update every place that uses source, like where you return text for LLMs:

import { llms } from 'fumadocs-core/source';
import { source } from '@/lib/source';

export const docsLlms = llms(source, {
  renderPage: (page) => {
    if (page.type === 'openapi') {
      // e.g. return the stringified OpenAPI schema
      return JSON.stringify(page.data.getSchema().bundled, null, 2);
    }

    // your original flow below...
  },
});

Render OpenAPI pages with <OpenAPIPage /> in your docs page:

app/docs/[[...slug]]/page.tsx
import { OpenAPIPage } from '@/components/api-page'; 

export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
  const params = await props.params;
  const page = source.getPage(params.slug);
  if (!page) notFound();

  if (page.type === 'openapi') {
    return (
      <DocsPage full>
        <DocsTitle>{page.data.title}</DocsTitle>
        <DocsBody>
          <OpenAPIPage {...page.data.getOpenAPIPageProps()} />
        </DocsBody>
      </DocsPage>
    );
  }

  // ...
}

Ensure the migration is complete!

Run a type check before continuing:

npm run types:check

To write MDX files into your content directory instead, see MDX Files.

Features

The official OpenAPI integration supports:

  • Basic API endpoint information
  • Interactive API playground
  • Example code to send request (in different programming languages)
  • Response samples and TypeScript definitions
  • Request parameters and body generated from schemas

Demo

View demo.

How is this guide?

Last updated on