[{"data":1,"prerenderedAt":70},["Reactive",2],{"blog-post-markdown-for-api-documentation":3},{"slug":4,"title":5,"description":6,"excerpt":7,"date":8,"category":9,"author":10,"keywords":11,"readingMinutes":12,"html":13,"headings":14,"tools":40,"related":44},"markdown-for-api-documentation","Markdown for API Documentation: OpenAPI, Stoplight, and the Docs-as-Code Stack","Writing API documentation with Markdown? This guide covers where Markdown lives in OpenAPI specs, how the major platforms handle it, and how to set up a docs-as-code workflow.","API documentation sits at the intersection of technical writing, software development, and developer experience. It's also one of the areas where Markdown has quietly become essential — often in…","2026-06-19","workflows","Matt Rathbone","api documentation markdown, openapi markdown, stoplight markdown, redocly markdown, api docs as code, markdown api docs, openapi description markdown, swagger documentation markdown, api reference docs",7,"\u003Cp>API documentation sits at the intersection of technical writing, software development, and developer experience. It&#39;s also one of the areas where Markdown has quietly become essential — often in ways that aren&#39;t obvious until you&#39;re knee-deep in an OpenAPI spec or fighting a Stoplight rendering issue.\u003C/p>\n\u003Cp>This guide covers where Markdown appears in API documentation, how the major platforms handle it, how to set up a docs-as-code workflow, and what to watch out for when writing descriptions that survive the journey from spec to rendered docs.\u003C/p>\n\u003Ch2 id=\"where-markdown-lives-in-an-openapi-spec\">Where Markdown Lives in an OpenAPI Spec\u003C/h2>\n\u003Cp>If you&#39;re working with OpenAPI (formerly Swagger), Markdown appears in several places:\u003C/p>\n\u003Cp>\u003Cstrong>Description fields\u003C/strong> are the most common. Nearly every object in the OpenAPI spec accepts a \u003Ccode>description\u003C/code> field, and these support CommonMark Markdown:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">info:\u003C/span>\n  \u003Cspan class=\"hljs-attr\">title:\u003C/span> \u003Cspan class=\"hljs-string\">Payments\u003C/span> \u003Cspan class=\"hljs-string\">API\u003C/span>\n  \u003Cspan class=\"hljs-attr\">version:\u003C/span> \u003Cspan class=\"hljs-string\">&quot;2.0&quot;\u003C/span>\n  \u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n    The **Payments API** lets you create, capture, and refund charges.\n\u003C/span>\n    \u003Cspan class=\"hljs-comment\">## Authentication\u003C/span>\n\n    \u003Cspan class=\"hljs-string\">All\u003C/span> \u003Cspan class=\"hljs-string\">requests\u003C/span> \u003Cspan class=\"hljs-string\">require\u003C/span> \u003Cspan class=\"hljs-string\">a\u003C/span> \u003Cspan class=\"hljs-string\">Bearer\u003C/span> \u003Cspan class=\"hljs-string\">token\u003C/span> \u003Cspan class=\"hljs-string\">in\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span> \u003Cspan class=\"hljs-string\">`Authorization`\u003C/span> \u003Cspan class=\"hljs-string\">header.\u003C/span>\n    \u003Cspan class=\"hljs-attr\">Rate limits apply:\u003C/span> \u003Cspan class=\"hljs-number\">100\u003C/span> \u003Cspan class=\"hljs-string\">requests/second\u003C/span> \u003Cspan class=\"hljs-string\">per\u003C/span> \u003Cspan class=\"hljs-string\">API\u003C/span> \u003Cspan class=\"hljs-string\">key.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>The \u003Ccode>description\u003C/code> field on paths, operations, parameters, request bodies, and response schemas all support Markdown:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">paths:\u003C/span>\n  \u003Cspan class=\"hljs-string\">/charges:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">post:\u003C/span>\n      \u003Cspan class=\"hljs-attr\">summary:\u003C/span> \u003Cspan class=\"hljs-string\">Create\u003C/span> \u003Cspan class=\"hljs-string\">a\u003C/span> \u003Cspan class=\"hljs-string\">charge\u003C/span>\n      \u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        Creates a new charge. The `amount` is in the **smallest currency unit**\n        (e.g., cents for USD, pence for GBP).\n\u003C/span>\n        \u003Cspan class=\"hljs-string\">See\u003C/span> [\u003Cspan class=\"hljs-string\">currency\u003C/span> \u003Cspan class=\"hljs-string\">codes\u003C/span>]\u003Cspan class=\"hljs-string\">(/docs/currencies)\u003C/span> \u003Cspan class=\"hljs-string\">for\u003C/span> \u003Cspan class=\"hljs-string\">a\u003C/span> \u003Cspan class=\"hljs-string\">full\u003C/span> \u003Cspan class=\"hljs-string\">list.\u003C/span>\n      \u003Cspan class=\"hljs-attr\">parameters:\u003C/span>\n        \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">idempotency_key\u003C/span>\n          \u003Cspan class=\"hljs-attr\">in:\u003C/span> \u003Cspan class=\"hljs-string\">header\u003C/span>\n          \u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n            A unique key to safely retry requests. If you send the same key twice,\n            the API returns the original response rather than creating a duplicate.\n\u003C/span>\n            \u003Cspan class=\"hljs-string\">Recommended\u003C/span> \u003Cspan class=\"hljs-string\">for\u003C/span> \u003Cspan class=\"hljs-string\">all\u003C/span> \u003Cspan class=\"hljs-string\">`POST`\u003C/span> \u003Cspan class=\"hljs-string\">requests.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>\u003Cstrong>Markdown guide files\u003C/strong> alongside the spec are the second major use case. Most teams write long-form content — tutorials, quickstart guides, authentication flows — as \u003Ccode>.md\u003C/code> files that live in the same repository as \u003Ccode>openapi.yaml\u003C/code>, versioned and reviewed together.\u003C/p>\n\u003Cp>\u003Cstrong>Changelog files\u003C/strong> are almost always Markdown. Your \u003Ccode>CHANGELOG.md\u003C/code> lives in git alongside the spec and gets rendered by whatever platform you use for documentation.\u003C/p>\n\u003Ch2 id=\"the-api-documentation-platforms-compared\">The API Documentation Platforms Compared\u003C/h2>\n\u003Cp>Most teams don&#39;t render OpenAPI specs manually — they use a platform that reads the spec and generates documentation. These platforms differ significantly in how they handle Markdown.\u003C/p>\n\u003Cdiv class=\"table-responsive\">\u003Ctable class=\"table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Platform\u003C/th>\n\u003Cth>Markdown in descriptions\u003C/th>\n\u003Cth>Custom Markdown pages\u003C/th>\n\u003Cth>Self-hostable\u003C/th>\n\u003Cth>Pricing model\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>\u003Cstrong>Redocly\u003C/strong>\u003C/td>\n\u003Ctd>Full CommonMark + extensions\u003C/td>\n\u003Ctd>Yes (docs-as-code)\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003Ctd>Open-source CLI; hosted plans\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Stoplight\u003C/strong>\u003C/td>\n\u003Ctd>Full CommonMark\u003C/td>\n\u003Ctd>Yes (separate \u003Ccode>.md\u003C/code> files)\u003C/td>\n\u003Ctd>Limited\u003C/td>\n\u003Ctd>Freemium SaaS\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Scalar\u003C/strong>\u003C/td>\n\u003Ctd>Full CommonMark\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003Ctd>Yes (open-source)\u003C/td>\n\u003Ctd>Open-source; hosted option\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Readme.io\u003C/strong>\u003C/td>\n\u003Ctd>CommonMark + custom blocks\u003C/td>\n\u003Ctd>Yes (guides section)\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003Ctd>Commercial SaaS\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>Swagger UI\u003C/strong>\u003C/td>\n\u003Ctd>Limited (sanitized HTML)\u003C/td>\n\u003Ctd>No (spec only)\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003Ctd>Open-source\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Cstrong>RapiDoc\u003C/strong>\u003C/td>\n\u003Ctd>CommonMark\u003C/td>\n\u003Ctd>No (spec only)\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003Ctd>Open-source\u003C/td>\n\u003C/tr>\n\u003C/tbody>\u003C/table>\u003C/div>\n\u003Cp>\u003Cstrong>Redocly\u003C/strong> is the go-to choice for teams who want full docs-as-code. You write OpenAPI + Markdown files, run \u003Ccode>redocly build-docs\u003C/code>, and get a self-hosted documentation site. Their \u003Ccode>@redocly/cli\u003C/code> also lints your OpenAPI spec for correctness, consistency, and style. Markdown support is robust: admonitions (callouts), tabs, code blocks with syntax highlighting, and cross-references between guides and reference docs.\u003C/p>\n\u003Cp>\u003Cstrong>Stoplight Studio\u003C/strong> is the most popular visual editor for OpenAPI. It renders Markdown in description fields faithfully and lets you write standalone Markdown pages that appear alongside the generated reference docs. The tradeoff: the visual editor can sometimes mangle complex Markdown in descriptions — always verify in preview mode before committing.\u003C/p>\n\u003Cp>\u003Cstrong>Scalar\u003C/strong> is newer and gaining momentum fast. It&#39;s fully open-source, renders OpenAPI specs with a modern, clean UI, and handles CommonMark properly in all description fields. Worth considering for teams who want something that looks great without vendor lock-in.\u003C/p>\n\u003Cp>\u003Cstrong>Readme.io\u003C/strong> is the commercial choice for teams that want a hosted developer portal with analytics, user authentication for private docs, and API key management built in. Their Markdown support includes custom callout blocks and interactive example makers. The tradeoff: more lock-in than the open-source alternatives, and the pricing climbs quickly.\u003C/p>\n\u003Cp>\u003Cstrong>Swagger UI\u003C/strong> is the original and still widely deployed — many teams use it for internal reference or expose it directly from their API. Its Markdown support is limited, though: descriptions pass through a sanitized HTML pipeline, and complex Markdown elements don&#39;t always behave as expected. Stick to basic formatting (bold, italic, inline code, links) if Swagger UI is your target.\u003C/p>\n\u003Ch2 id=\"setting-up-docs-as-code-for-api-documentation\">Setting Up Docs-as-Code for API Documentation\u003C/h2>\n\u003Cp>The docs-as-code approach treats documentation like code: stored in git, reviewed in pull requests, deployed through CI/CD. For API docs, this means your repository looks something like:\u003C/p>\n\u003Cpre>\u003Ccode>api-docs/\n├── openapi.yaml\n├── docs/\n│   ├── getting-started.md\n│   ├── authentication.md\n│   ├── rate-limits.md\n│   └── changelog.md\n├── redocly.yaml\n└── .github/\n    └── workflows/\n        └── docs.yml\n\u003C/code>\u003C/pre>\u003Cp>A minimal GitHub Actions workflow with Redocly:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">API\u003C/span> \u003Cspan class=\"hljs-string\">Docs\u003C/span>\n\n\u003Cspan class=\"hljs-attr\">on:\u003C/span>\n  \u003Cspan class=\"hljs-attr\">push:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">branches:\u003C/span> [\u003Cspan class=\"hljs-string\">main\u003C/span>]\n  \u003Cspan class=\"hljs-attr\">pull_request:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">branches:\u003C/span> [\u003Cspan class=\"hljs-string\">main\u003C/span>]\n\n\u003Cspan class=\"hljs-attr\">jobs:\u003C/span>\n  \u003Cspan class=\"hljs-attr\">lint-and-build:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">runs-on:\u003C/span> \u003Cspan class=\"hljs-string\">ubuntu-latest\u003C/span>\n    \u003Cspan class=\"hljs-attr\">steps:\u003C/span>\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/checkout@v4\u003C/span>\n\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Install\u003C/span> \u003Cspan class=\"hljs-string\">Redocly\u003C/span> \u003Cspan class=\"hljs-string\">CLI\u003C/span>\n        \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">npm\u003C/span> \u003Cspan class=\"hljs-string\">install\u003C/span> \u003Cspan class=\"hljs-string\">-g\u003C/span> \u003Cspan class=\"hljs-string\">@redocly/cli\u003C/span>\n\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Lint\u003C/span> \u003Cspan class=\"hljs-string\">OpenAPI\u003C/span> \u003Cspan class=\"hljs-string\">spec\u003C/span>\n        \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">redocly\u003C/span> \u003Cspan class=\"hljs-string\">lint\u003C/span> \u003Cspan class=\"hljs-string\">openapi.yaml\u003C/span>\n\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Build\u003C/span> \u003Cspan class=\"hljs-string\">docs\u003C/span>\n        \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">redocly\u003C/span> \u003Cspan class=\"hljs-string\">build-docs\u003C/span> \u003Cspan class=\"hljs-string\">openapi.yaml\u003C/span> \u003Cspan class=\"hljs-string\">--output\u003C/span> \u003Cspan class=\"hljs-string\">dist/\u003C/span>\n\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Deploy\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">GitHub\u003C/span> \u003Cspan class=\"hljs-string\">Pages\u003C/span>\n        \u003Cspan class=\"hljs-attr\">if:\u003C/span> \u003Cspan class=\"hljs-string\">github.ref\u003C/span> \u003Cspan class=\"hljs-string\">==\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;refs/heads/main&#x27;\u003C/span>\n        \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">peaceiris/actions-gh-pages@v3\u003C/span>\n        \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n          \u003Cspan class=\"hljs-attr\">github_token:\u003C/span> \u003Cspan class=\"hljs-string\">${{\u003C/span> \u003Cspan class=\"hljs-string\">secrets.GITHUB_TOKEN\u003C/span> \u003Cspan class=\"hljs-string\">}}\u003C/span>\n          \u003Cspan class=\"hljs-attr\">publish_dir:\u003C/span> \u003Cspan class=\"hljs-string\">dist/\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>The \u003Ccode>redocly lint\u003C/code> step catches spec errors and missing descriptions before they reach production. For Markdown files, adding \u003Ca href=\"https://github.com/DavidAnson/markdownlint\">markdownlint\u003C/a> to the same workflow catches style issues in your guide files — the same rules you&#39;d run locally with our \u003Ca href=\"/tools/markdown-linter\">Markdown Linter\u003C/a>.\u003C/p>\n\u003Ch2 id=\"writing-good-markdown-api-descriptions\">Writing Good Markdown API Descriptions\u003C/h2>\n\u003Cp>The descriptions in your OpenAPI spec are often the first thing a developer reads about an endpoint. A few principles that make a meaningful difference:\u003C/p>\n\u003Cp>\u003Cstrong>Lead with the &quot;what&quot;, not the &quot;how&quot;.\u003C/strong> The operation name already tells you what it does; the description should explain when to use it and what to watch for.\u003C/p>\n\u003Cp>Instead of:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">Creates\u003C/span> \u003Cspan class=\"hljs-string\">a\u003C/span> \u003Cspan class=\"hljs-string\">user\u003C/span> \u003Cspan class=\"hljs-string\">in\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span> \u003Cspan class=\"hljs-string\">database.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>Write:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n  Creates a new user account. Returns the created user object including the generated `id`.\n\u003C/span>\n  \u003Cspan class=\"hljs-string\">**Rate\u003C/span> \u003Cspan class=\"hljs-string\">limit:**\u003C/span> \u003Cspan class=\"hljs-number\">10\u003C/span> \u003Cspan class=\"hljs-string\">requests/minute\u003C/span> \u003Cspan class=\"hljs-string\">per\u003C/span> \u003Cspan class=\"hljs-string\">IP.\u003C/span> \u003Cspan class=\"hljs-string\">Creating\u003C/span> \u003Cspan class=\"hljs-string\">users\u003C/span> \u003Cspan class=\"hljs-string\">in\u003C/span> \u003Cspan class=\"hljs-string\">bulk?\u003C/span> \u003Cspan class=\"hljs-string\">Use\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span>\n  [\u003Cspan class=\"hljs-string\">batch\u003C/span> \u003Cspan class=\"hljs-string\">import\u003C/span> \u003Cspan class=\"hljs-string\">endpoint\u003C/span>]\u003Cspan class=\"hljs-string\">(/reference/users/import)\u003C/span> \u003Cspan class=\"hljs-string\">instead.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>\u003Cstrong>Always show the unit, not just the type.\u003C/strong> For numeric fields, clarify what the number represents:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">parameters:\u003C/span>\n  \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">amount\u003C/span>\n    \u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n      The charge amount in the **smallest currency unit** for the given currency.\n      For USD: `100` = $1.00. For JPY (zero-decimal): `100` = ¥100.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>\u003Cstrong>Use code fences for examples.\u003C/strong> Most platforms (Redocly, Stoplight, Scalar) syntax-highlight fenced code blocks in description fields:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-attr\">description:\u003C/span> \u003Cspan class=\"hljs-string\">|\n  Include a unique idempotency key on every `POST` request:\n\u003C/span>\n  \u003Cspan class=\"hljs-string\">```\u003C/span>\n  \u003Cspan class=\"hljs-attr\">X-Idempotency-Key:\u003C/span> \u003Cspan class=\"hljs-number\">550e8400\u003C/span>\u003Cspan class=\"hljs-string\">-e29b-41d4-a716-446655440000\u003C/span>\n  \u003Cspan class=\"hljs-string\">```\u003C/span>\n\n  \u003Cspan class=\"hljs-string\">Keys\u003C/span> \u003Cspan class=\"hljs-string\">expire\u003C/span> \u003Cspan class=\"hljs-string\">after\u003C/span> \u003Cspan class=\"hljs-number\">24\u003C/span> \u003Cspan class=\"hljs-string\">hours.\u003C/span> \u003Cspan class=\"hljs-string\">Reusing\u003C/span> \u003Cspan class=\"hljs-string\">an\u003C/span> \u003Cspan class=\"hljs-string\">expired\u003C/span> \u003Cspan class=\"hljs-string\">key\u003C/span> \u003Cspan class=\"hljs-string\">creates\u003C/span> \u003Cspan class=\"hljs-string\">a\u003C/span> \u003Cspan class=\"hljs-string\">new\u003C/span> \u003Cspan class=\"hljs-string\">request.\u003C/span>\n\u003C/code>\u003C/pre>\u003Cp>Note the nested code fences here — a triple-backtick block inside a YAML string. Most OpenAPI renderers handle this correctly; Swagger UI is the common exception.\u003C/p>\n\u003Cp>\u003Cstrong>Link between operations.\u003C/strong> Relative links (\u003Ccode>[see also](/reference/refunds)\u003C/code>) connect related endpoints and keep users in the docs. Most platforms render these as proper links; the Markdown source stays readable in the raw spec.\u003C/p>\n\u003Ch2 id=\"what-doesnt-work-well\">What Doesn&#39;t Work Well\u003C/h2>\n\u003Cp>\u003Cstrong>Complex tables in Swagger UI.\u003C/strong> Swagger UI renders Markdown tables inconsistently — the cell contents are sometimes sanitized in ways that strip inline formatting. Test tables in your target platform before relying on them for critical information.\u003C/p>\n\u003Cp>\u003Cstrong>Nested code blocks.\u003C/strong> Showing a code block example that \u003Cem>contains\u003C/em> another code block (meta-documentation) trips up some renderers. If you need to demonstrate nested fences, use an indented code block (4 spaces) for the inner example instead of triple backticks.\u003C/p>\n\u003Cp>\u003Cstrong>HTML in descriptions.\u003C/strong> OpenAPI allows HTML in description fields, and CommonMark allows inline HTML in Markdown. But documentation platforms sanitize it — \u003Ccode>&lt;script&gt;\u003C/code>, \u003Ccode>&lt;iframe&gt;\u003C/code>, \u003Ccode>&lt;style&gt;\u003C/code>, and sometimes even \u003Ccode>&lt;details&gt;\u003C/code> get stripped. Don&#39;t rely on raw HTML for anything load-bearing.\u003C/p>\n\u003Cp>\u003Cstrong>Relative paths across platforms.\u003C/strong> A link like \u003Ccode>[authentication](/docs/authentication)\u003C/code> works perfectly when self-hosting with Redocly but breaks in Stoplight if your docs live at a different base path. Always test cross-links in the actual deployed environment.\u003C/p>\n\u003Ch2 id=\"checking-your-markdown-before-it-ships\">Checking Your Markdown Before It Ships\u003C/h2>\n\u003Cp>Before committing an updated OpenAPI spec or guide file:\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Run the platform&#39;s linter.\u003C/strong> \u003Ccode>redocly lint openapi.yaml\u003C/code> catches spec-level issues; \u003Ccode>markdownlint\u003C/code> catches Markdown style problems in your \u003Ccode>.md\u003C/code> files.\u003C/li>\n\u003Cli>\u003Cstrong>Preview in the target platform.\u003C/strong> What looks right in VS Code may render differently in Stoplight or Readme.io — especially for tables and nested code blocks.\u003C/li>\n\u003Cli>\u003Cstrong>Check every code block manually.\u003C/strong> Unterminated fences are the most common rendering failure. They can silently swallow everything below them.\u003C/li>\n\u003Cli>\u003Cstrong>Verify all cross-links.\u003C/strong> Use a link-checker in CI for large doc sets; manual spot-checking for smaller ones.\u003C/li>\n\u003C/ol>\n\u003Cp>For catching Markdown style issues locally before pushing, the \u003Ca href=\"/tools/markdown-linter\">Markdown Linter\u003C/a> at Markdown Tools checks heading hierarchy, bare URLs, missing alt text, unclosed code blocks, and more. The \u003Ca href=\"/tools/markdown-editor\">Markdown Editor\u003C/a> gives you live preview so you can see how your guide content will look before it hits the platform.\u003C/p>\n\u003Ch2 id=\"platform-support-quick-reference\">Platform Support Quick Reference\u003C/h2>\n\u003Cdiv class=\"table-responsive\">\u003Ctable class=\"table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Format\u003C/th>\n\u003Cth>OpenAPI descriptions\u003C/th>\n\u003Cth>Guide \u003Ccode>.md\u003C/code> files\u003C/th>\n\u003Cth>Swagger UI\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>Bold, italic\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Inline code\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Fenced code blocks\u003C/td>\n\u003Ctd>Redocly, Stoplight, Scalar, Readme\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>Limited\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Tables\u003C/td>\n\u003Ctd>Redocly, Stoplight, Scalar, Readme\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>Inconsistent\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Links\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>All platforms\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Task lists\u003C/td>\n\u003Ctd>Some\u003C/td>\n\u003Ctd>Redocly, Readme\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Footnotes\u003C/td>\n\u003Ctd>Some\u003C/td>\n\u003Ctd>Redocly (MDX), Readme\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Admonitions / callouts\u003C/td>\n\u003Ctd>Redocly, Readme (custom blocks)\u003C/td>\n\u003Ctd>Redocly, Readme\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Raw HTML\u003C/td>\n\u003Ctd>Varies — most sanitize\u003C/td>\n\u003Ctd>Varies\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003C/tbody>\u003C/table>\u003C/div>\n\u003Ch2 id=\"related-resources\">Related Resources\u003C/h2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"/tools/markdown-linter\">Markdown Linter\u003C/a> — catch style issues before committing\u003C/li>\n\u003Cli>\u003Ca href=\"/tools/markdown-editor\">Markdown Editor\u003C/a> — live preview while drafting guide content\u003C/li>\n\u003Cli>\u003Ca href=\"/tools/markdown-to-html\">Markdown to HTML\u003C/a> — export clean HTML for platforms that accept HTML\u003C/li>\n\u003Cli>Our guide: \u003Ca href=\"/blog/markdown-for-technical-writers-docs-as-code\">Markdown for Technical Writers: The Docs-as-Code Workflow\u003C/a>\u003C/li>\n\u003Cli>Our guide: \u003Ca href=\"/blog/markdown-syntax-highlighting-complete-guide\">Markdown Syntax Highlighting\u003C/a> — getting language tags right in code blocks\u003C/li>\n\u003Cli>Our guide: \u003Ca href=\"/blog/mkdocs-vs-docusaurus-vs-gitbook\">MkDocs vs Docusaurus vs GitBook\u003C/a> — choosing the right docs platform\u003C/li>\n\u003C/ul>\n",[15,19,22,25,28,31,34,37],{"id":16,"text":17,"level":18},"where-markdown-lives-in-an-openapi-spec","Where Markdown Lives in an OpenAPI Spec",2,{"id":20,"text":21,"level":18},"the-api-documentation-platforms-compared","The API Documentation Platforms Compared",{"id":23,"text":24,"level":18},"setting-up-docs-as-code-for-api-documentation","Setting Up Docs-as-Code for API Documentation",{"id":26,"text":27,"level":18},"writing-good-markdown-api-descriptions","Writing Good Markdown API Descriptions",{"id":29,"text":30,"level":18},"what-doesnt-work-well","What Doesn't Work Well",{"id":32,"text":33,"level":18},"checking-your-markdown-before-it-ships","Checking Your Markdown Before It Ships",{"id":35,"text":36,"level":18},"platform-support-quick-reference","Platform Support Quick Reference",{"id":38,"text":39,"level":18},"related-resources","Related Resources",[41,42,43],"markdown-linter","markdown-editor","markdown-to-html",[45,52,62],{"slug":46,"title":47,"description":48,"excerpt":49,"date":50,"category":9,"author":10,"keywords":51,"readingMinutes":12},"markdown-for-technical-writers-docs-as-code","Markdown for Technical Writers: The Docs-as-Code Workflow Guide","How to set up a docs-as-code workflow with Markdown, Git, and a static site generator — practical guidance for technical writers moving away from wiki-based tools.","\"Docs-as-code\" is the practice of treating documentation the same way software teams treat code: write in plain text (usually Markdown), version-control in Git, review through pull requests, and…","2026-05-15","docs as code, markdown technical writing, documentation workflow, markdownlint, vale prose linter, mkdocs markdown, docusaurus technical writing, docs as code workflow",{"slug":53,"title":54,"description":55,"excerpt":56,"date":57,"category":58,"author":59,"keywords":60,"readingMinutes":61},"markdown-code-annotations-documentation-complete-guide","Markdown Code Annotations and Documentation: Complete Guide for Technical Writing","Master code annotations, inline documentation, and technical writing in Markdown. Learn to create annotated code examples, documentation comments, and professional technical guides with proper formatting.","Code annotations and documentation in Markdown bridge the gap between raw code examples and comprehensive technical explanations, enabling writers to create clear, educational content that helps…","2025-08-31","Tutorial","Matthew Rathbone","markdown code annotations, markdown documentation, code comments markdown, technical writing markdown, annotated code examples, markdown code blocks, documentation comments",20,{"slug":63,"title":64,"description":65,"excerpt":66,"date":67,"category":58,"author":59,"keywords":68,"readingMinutes":69},"markdown-nested-code-blocks-and-escaping-guide","Markdown Nested Code Blocks and Escaping: Complete Guide for Complex Documentation","Master advanced Markdown code block techniques including nested blocks, proper escaping, and handling complex code examples in documentation. Learn best practices for technical writing.","When creating technical documentation with Markdown, one of the most challenging aspects is properly displaying complex code examples, especially when you need to show how to write Markdown code…","2025-10-15","markdown nested code blocks, markdown code escaping, nested backticks markdown, markdown documentation, code block syntax, markdown technical writing, complex code examples",4,1792184946849]