WritedocsWritedocs

Multi-spec sites and overrides

Multiple specs in one site

Any number of navigation groups can use openapi, each pointing at its own spec — for example, a public REST API and an internal admin API, documented in the same site:

{
  "navigation": [
    "index",
    {
      "group": "REST API",
      "openapi": { "src": "rest-api.yaml", "path": "/api/rest" }
    },
    {
      "group": "Admin API",
      "openapi": { "src": "admin-api.yaml", "path": "/api/admin" }
    }
  ]
}

Each group’s path is also its namespace on disk for the generated build output, so every openapi group in a writedocs.json must use a distinct path — the build fails with a clear error naming both groups if two collide.

An openapi group can also be nested — inside another hand-authored group, inside a tab, inside a version, at any depth — the same as an ordinary group can be. Useful for something like a tab specifically for “API Reference” that itself splits into multiple specs:

{
  "navigation": {
    "tabs": [
      { "tab": "Guides", "pages": ["index"] },
      {
        "tab": "API Reference",
        "pages": [
          { "group": "REST", "openapi": { "src": "rest-api.yaml", "path": "/api/rest" } },
          { "group": "GraphQL", "openapi": { "src": "graphql-api.yaml", "path": "/api/graphql" } }
        ]
      }
    ]
  }
}

Hand-written overrides

Sometimes one specific operation deserves real prose — a longer explanation, extra examples, a warning about a gotcha — while every other operation is fine auto-generated. Write the page yourself under docs/, and set its openapi frontmatter field to the exact "METHOD /path" the spec uses:

docs/api/get-pet.mdx
---
title: Get a pet by ID
description: Retrieve a single pet's details, with troubleshooting notes for the common 404 case.
openapi: "GET /pets/{petId}"
---

This endpoint 404s if the pet was soft-deleted rather than removed outright — check the
`X-Deleted-At` response header before assuming the ID is simply wrong.

The build matches this page against the spec by that key. When it matches:

  • This page is served instead of the generated stub for that one operation — your prose renders above the same Try-it playground and parameter/response reference the generated version would have had.
  • Every other operation in the spec still gets its normal generated page.

Override matching is by operation key ("METHOD /path"), shared across every openapi group in the site — not scoped to one specific spec. In practice a method+path colliding across two genuinely unrelated specs mounted in the same site is rare enough this hasn’t needed to be more precise.

Reference the page’s slug in writedocs.json’s navigation like any other hand-written page — it doesn’t need special treatment there, only the openapi frontmatter field on the page itself.