engineering
Stop Renting Your OpenAPI Docs
Turn an OpenAPI spec into a good-looking docs site you can host yourself. What to keep, what to check, and where guides, examples, and URLs complicate a move.
An OpenAPI file is portable. The documentation built around it often is not.
The spec can live in your repo as YAML or JSON and move between renderers. That is useful when an API changes hands, or when a team wants to change its docs without rewriting the contract.
The harder part to move is often everything added around the spec: guides, examples, navigation, and page URLs.
What the field gives you
Swagger UI gives a project a direct way to render an OpenAPI reference. It does not write the surrounding guides or decide how that reference fits into a larger docs site.
Redocly’s open-source CLI can also build an HTML reference you host yourself. There are good free options here. Teams still need to decide where their guides, architecture notes, and changelog live, and how readers move between them and the reference.
Hosted docs services can give a team a polished reference quickly. Before choosing one, try exporting a guide with custom components and rebuilding it somewhere else. The OpenAPI file may travel cleanly while the material around it needs work.
You can also assemble a docs site yourself with a site generator and an OpenAPI renderer. That gives you control, along with responsibility for keeping the pieces working together.
For us, the useful test was simpler: could one build put the API reference beside the guides and leave us with files we could host ourselves?
And could it look good enough that we actually wanted to send people there? A docs site is often someone’s first proper look at a project. We wanted clear type, useful navigation, and room to read the examples, without making every API team build a frontend to get them.
What you actually want
The OpenAPI file should stay where the API team maintains it.
The renderer should read it directly and put the API reference beside the project’s guides, recipes, architecture notes, and changelog. Plain-text context exports should describe the same published reference. If the project also has an MCP manifest, it can be another input to the site; an OpenAPI renderer does not turn an HTTP API into a running MCP server.
That is the setup we built Sourcey for.
How
Sourcey reads OpenAPI directly. With an introduction.md, a quickstart.md, and an openapi.yaml beside the config, a small site looks like this:
import { defineConfig, markdown, openapi } from "sourcey";
export default defineConfig({
name: "My API",
navigation: {
tabs: [
{
tab: "Guides",
slug: "",
source: markdown({
groups: [{
group: "Start here",
pages: ["introduction", "quickstart"],
}],
}),
},
{ tab: "API", slug: "api", source: openapi("./openapi.yaml") },
],
},
});
That produces an API tab generated from the spec, with operation anchors, schema links, examples, search entries, a sitemap entry, and plain-text context files beside the project’s other pages.
The build reads the spec where it lives, without converting it to MDX or another vendor template language. The OpenAPI YAML stays in the repo; moving the surrounding guides and URLs still needs a separate check.
Keep the API checks
Changing the renderer should not remove the spec’s linting or validation from CI. A readable page can faithfully render a wrong schema. Review authentication requirements, request examples, error responses, and references against the API you ship.
Check vendor extensions separately. Fields beginning with x- can carry useful examples or presentation settings, but support varies between renderers. Try the operations that use them before assuming the new site will reproduce every detail.
If users rely on an interactive request console, account for that too. Sourcey builds reference pages and code samples; it does not replace Swagger UI’s request runner. You can keep a console alongside the docs and feed both the same spec. That is often less work than rebuilding a tool your users already know.
Move the reference graph, not just the front door
A spec split across files is still one contract. If openapi.yaml refers to ./schemas/order.yaml, copying only the top-level file leaves a hole. Keep the referenced files and their relative locations together. OpenAPI resolves relative references against a base URI; Schema Objects can also establish a base with $id. Moving a file can change what its references mean.1
Try an operation whose response uses a shared schema, then follow a nested type. A page of endpoint names is an easy demonstration. A response linked through two files is a better migration check.
Authentication has two separate jobs here. The spec’s security schemes describe credentials for calling the API. They do not put a login screen in front of the documentation. If the reference itself is private, your hosting must enforce that access rule on the HTML, search data, and context exports as well. A bearer-token example on a public page does not make the page private.
Finally, keep an example of an unsuccessful request beside the happy path. A documented 401 or 429 response tells someone whether to change credentials, wait, or change their request. A beautiful reference that sends every failure to the same generic troubleshooting page leaves the hardest part of integration to the reader.
Cheesestore, in public

Cheesestore is a public demo with guides, an MCP fixture, and an API reference generated from one YAML file. Open an operation, follow its schema links, and compare the result with the input. The same Sourcey renderer handles C++ source for Icey’s C++ reference and Go packages for Scafld’s Go reference.
The cheese service is fictional. The generated reference and the files you can inspect are real.
Try the exit
If portability matters to your team, test the whole docs build. Choose one guide with custom components, one complicated operation, and one schema linked from several places. Build them, serve the output on a second host, and follow the old links into it.
Record the old and new operation URLs, including fragment identifiers. Having an operationId in the spec does not force two renderers to use the same URL. A redirect can move a page; preserving links to individual operations may also require matching anchors. Check a few links from real issues and support replies before moving the domain.