Your OpenAPI file is the source of truth for your API: paths, parameters, request bodies, response schemas, and examples. But raw YAML or JSON is not the best format for everyday review. Backend engineers need a quick endpoint reference in the repo. Frontend developers need request/response fields they can scan in a PR. Technical writers need content they can paste into a wiki without rewriting the schema.
Markdown is the practical output format for that workflow. It renders in GitHub, Confluence, Notion, static site generators, and plain text editors. The implementation goal is simple: take an existing openapi.yaml and generate clean Markdown automatically so the docs stay aligned with the API.
Why generate Markdown from OpenAPI?
An OpenAPI document is machine-readable by design. Tools use it to generate clients, validate requests, run contract tests, and render interactive docs.
Markdown solves a different problem: distributing API information to humans in places that do not run an OpenAPI renderer.
Common use cases:
- Add an API reference to
README.mdor/docs. - Include endpoint details in pull request descriptions.
- Publish API contracts in Confluence, Notion, or an internal wiki.
- Feed a static documentation site built with Docusaurus, MkDocs, or Hugo.
The important part is automation. A Markdown file written manually will drift. A Markdown file regenerated from the OpenAPI spec on every change stays accurate.
Before generating docs, validate the spec itself. If the source is broken, the output will be broken too. For validation options, see the OpenAPI validator tools guide.
Choose a conversion method
There is no single official OpenAPI command for Markdown export. In practice, you choose from converters, custom scripts, or an API documentation platform.
| Method | Best for | Output |
|---|---|---|
openapi-to-md / openapi-markdown
|
Fast Markdown generation with minimal setup | Single Markdown file or schema tables |
| Widdershins | Static docs sites with code samples | Themeable Markdown with language tabs |
| Custom script | Team-specific layout | Whatever you template |
| Apidog | Spec import, hosted docs, and tests in one workspace | Rendered docs plus Markdown content blocks |
Method 1: Generate Markdown with a one-line converter
If you only need a quick repo reference, use a dedicated converter.
For Node.js projects, openapi-to-md can convert OpenAPI v2 or v3 YAML/JSON into Markdown:
npx openapi-to-md openapi.yaml api-reference.md
For Python workflows, openapi-markdown provides a similar command:
pip install openapi-markdown
openapi2markdown openapi.yaml api-reference.md
These tools read the spec, walk the paths and schemas, and generate headings, parameter tables, and response sections.
Use this when:
- You want a single generated reference file.
- The default layout is acceptable.
- You want minimal setup.
Avoid this when:
- You need custom section ordering.
- You need language-specific code samples.
- You need one page per tag/resource.
Method 2: Use Widdershins for docs sites and code samples
Widdershins converts OpenAPI/Swagger files into Slate-compatible Markdown. It is useful when your Markdown feeds a documentation site and you want code tabs.
Install and run it:
npm install -g widdershins
widdershins openapi.yaml -o api-reference.md
Add language tabs:
widdershins \
--language_tabs 'shell:cURL' 'python:Python' 'javascript:JavaScript' \
--omitHeader \
openapi.yaml \
-o api-reference.md
Use --omitHeader when your static site generator adds its own front matter or page wrapper.
Widdershins is a good fit when:
- You publish docs with Docusaurus, MkDocs, Hugo, or a similar tool.
- You want code samples next to endpoints.
- You need more control than a basic converter provides.
The trade-off: you now own a template and a build step.
Method 3: Write a custom generator for an exact layout
If no converter matches your internal documentation style, parse the OpenAPI file and generate Markdown yourself.
This minimal Node.js script lists each operation and its parameters:
import { readFileSync, writeFileSync } from "node:fs";
import yaml from "js-yaml";
const spec = yaml.load(readFileSync("openapi.yaml", "utf8"));
const lines = [
`# ${spec.info.title}`,
"",
spec.info.description ?? "",
"",
];
for (const [path, methods] of Object.entries(spec.paths)) {
for (const [method, op] of Object.entries(methods)) {
lines.push(`## ${method.toUpperCase()} ${path}`);
lines.push("");
lines.push(op.summary ?? "");
lines.push("");
const params = op.parameters ?? [];
if (params.length) {
lines.push("| Name | In | Required | Description |");
lines.push("| ---- | -- | -------- | ----------- |");
for (const p of params) {
lines.push(
`| ${p.name} | ${p.in} | ${p.required ? "yes" : "no"} | ${p.description ?? ""} |`
);
}
lines.push("");
}
}
}
writeFileSync("api-reference.md", lines.join("\n"));
Install the YAML parser:
npm install js-yaml
Run the script:
node generate-docs.js
Extend it as needed:
- Split files by tag.
- Add request body schemas.
- Add response examples.
- Add authentication notes.
- Generate an endpoint index.
- Match your internal table format.
Use this method when the generated structure matters more than broad OpenAPI feature coverage. If you want to compare maintained tools before writing your own, see this roundup of API documentation generators with Markdown export.
Method 4: Keep specs, docs, and tests together in Apidog
One-shot converters generate Markdown, but the output can still drift if nobody reruns the command.
Apidog approaches this differently. You import your existing openapi.yaml, and Apidog reads the paths, schemas, and examples into a project. From there, it generates hosted API documentation from the imported spec without a separate Markdown build step.
Useful starting points:
Apidog is useful when you want generated reference docs and hand-written content in the same workspace. You can add Markdown content blocks for:
- Getting started guides
- Authentication notes
- Changelogs
- Usage examples
- Internal review notes
See these documentation creation tips with Apidog Markdown for the authoring workflow.
The same imported spec can also become the basis for tests. You build requests and assertions against the endpoints defined by the spec, then run them to verify that the live API still matches the contract.
To try that workflow, download Apidog, import your spec, and open the generated docs in the project.
Automate Markdown generation in CI
A converter you run manually will eventually be forgotten. Run generation automatically whenever the OpenAPI spec changes.
Here is a GitHub Actions workflow that regenerates docs/api-reference.md when openapi.yaml changes:
name: Generate API docs
on:
push:
paths:
- "openapi.yaml"
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Convert spec to Markdown
run: npx openapi-to-md openapi.yaml docs/api-reference.md
- name: Commit regenerated docs
run: |
git config user.name "docs-bot"
git config user.email "docs-bot@users.noreply.github.com"
git add docs/api-reference.md
git diff --staged --quiet || git commit -m "docs: regenerate API reference"
git push
This keeps the generated Markdown at most one commit behind the spec.
You can swap the conversion step for Widdershins:
- name: Convert spec to Markdown
run: |
npm install -g widdershins
widdershins \
--language_tabs 'shell:cURL' 'python:Python' 'javascript:JavaScript' \
--omitHeader \
openapi.yaml \
-o docs/api-reference.md
Or call your custom script:
- name: Convert spec to Markdown
run: node scripts/generate-docs.js
Add contract tests to the same pipeline
Generated docs are only useful if the OpenAPI spec still matches the live API. Add a test step after generation.
The Apidog CLI can run test scenarios headlessly:
npm install -g apidog-cli
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -r cli
If an assertion fails, the command exits non-zero and fails the build.
References:
This gives you a tighter loop:
- OpenAPI spec changes.
- Markdown docs regenerate.
- API contract tests run.
- CI blocks stale or inaccurate documentation.
Clean up generated Markdown
Generated Markdown usually needs a few rules to stay readable.
- Strip front matter when your renderer does not need it. Widdershins supports
--omitHeader. - Decide whether to generate one file or split by tag/resource.
- Keep examples realistic in the OpenAPI spec. Most converters reuse
exampleandexamplesvalues. - Do not hand-edit generated files. Put manual content in separate Markdown files.
- Validate the spec before generating docs.
If the output looks messy, fix the source spec first. Cleaner OpenAPI produces cleaner Markdown. The OpenAPI validator tools post covers tools for catching issues before generation.
Which method should you use?
Use this as a quick decision guide:
- Need a simple repo reference? Use
openapi-to-mdoropenapi-markdown. - Building a docs site with code tabs? Use Widdershins.
- Need a strict internal layout? Write a small custom generator.
- Want hosted docs, Markdown content, imported specs, and tests in one workspace? Use Apidog.
These approaches can also be combined. For example, you can use Apidog for hosted docs and testing, while also generating a Markdown reference in CI for offline repo browsing.
Final workflow
Treat Markdown as a generated artifact, not the source of truth.
A practical implementation looks like this:
- Maintain
openapi.yamlas the canonical API contract. - Validate the spec before publishing.
- Generate Markdown with a converter, Widdershins, or a custom script.
- Run generation in CI whenever the spec changes.
- Run API tests to confirm the implementation still matches the contract.
- Keep hand-written guides separate from generated reference files.
Once that pipeline is in place, your Markdown docs stay useful because they are continuously regenerated from the same OpenAPI contract your tools and tests already depend on.
Top comments (0)