Skip to content

Docsio v2 is out

See changelog
← Docsio Research

Documentation engineering · Research synthesis

Will your Markdown guide still work on a second site?

What GitHub, CommonMark, MkDocs, Pandoc and MDX reveal about publishing one guide twice, with a worked example for checking tables, links and commands.

By Docsio Research14 min read

A retry guide can look finished in two places while giving different instructions. A table can lose a condition, a link can open the wrong section and an example can copy the wrong command. This report uses published specifications and tool documentation to show how to decide which differences matter. It includes a small acceptance exercise for anyone maintaining one guide in a repository and on a documentation site.

Key findings

  • CommonMark 0.31.2 ships 652 numbered examples, including 29 in its fenced code blocks section. They specify how to interpret example text. They do not test the links, assets or reader tasks on an assembled documentation site. Specification Example corpus

  • The GFM specification shows how a value can remain in the source and disappear from a rendered table. In example 204, a body row has more cells than the header. The expected HTML omits the extra cell. GFM tables

  • GitHub resolves repository links in branch context. MkDocs can rewrite a link to a Markdown file into a link to a built page while retaining its fragment. For a shared troubleshooting guide, check which version, page and section a reader actually reaches. GitHub MkDocs

How we researched this

On November 3, 2026, we inspected the pinned CommonMark and GFM specifications, the CommonMark example corpus, RFC 7763 and the original documentation for the named tools. To reproduce the corpus count, read the JSON array at the cited URL, count entries and distinct example numbers, then count entries whose section field is exactly “Fenced code blocks”. We used documented behavior to design a fictional retry guide and an acceptance exercise. We did not run vendor implementations against one another or measure the prevalence of defects across published sites.

Decide what has to survive the second rendering

Imagine an engineer reading an older release of your retry guide in a repository. A support rep sends the same guide from the public docs site. Both readers need to answer one question before changing a production setting. Does the maximum include the first attempt, or does it count only retries? A color change is harmless here. Losing a small qualification in the defaults table could change how many requests the engineer sends.

Write down the answer both copies must give before choosing any tooling. For this fictional guide, suppose the product permits two retries after the initial request. The maximum is three requests. Assume this rule belongs to version 2 of our example product. Those are invented requirements for the exercise, not settings of an actual service. A screenshot comparison might catch a missing column. It cannot establish that both readers saw the version 2 rule.

We suggest a short publishing agreement with four entries:

EntryExample for the retry guide
Supported destinationsThe repository at a version 2 release tag and the public version 2 docs
Essential factsTwo retries follow the first request. The unit is a request, not a second
Required actionsFind the default, copy a settings example and reach the troubleshooting section
Acceptable differencesDifferent fonts, code colors and navigation controls

Keep the agreement with the source. If someone adds a third destination, such as a downloadable manual, the existing record gives the team something concrete to review. They can decide whether that edition must support interactive examples, whether it should contain a static substitute and who will maintain it. Nothing in a filename answers those editorial questions.

What counts as evidence of Markdown compatibility?

In its March 2016 registration for the Markdown media type, RFC 7763 describes an optional variant identifier. It gives the receiver a hint about the author’s intended dialect. A file labeled as Markdown therefore leaves an important question open: which interpretation does this publisher actually use? RFC 7763, section 2

CommonMark version 0.31.2, dated January 28, 2024 on the specification itself, offers a precise kind of evidence. Its examples pair source text with expected output and are intended for parser conformance testing. The JSON for version 0.31.2 has 652 entries with 652 distinct example numbers. Of those entries, 29 belong to the fenced code blocks section. The denominator is examples in this version. Neither count measures the number of parsers that pass, the proportion of portable guides or the likelihood of a defect. CommonMark Versioned JSON

GitHub’s published GFM specification is version 0.29-gfm, dated April 6, 2019. It describes extensions and says that GitHub performs additional processing on the resulting HTML. Read each document against its own version and scope. In particular, the CommonMark 0.31.2 corpus is not a compliance certificate for the GitHub website. GFM introduction

For a documentation team, each of these evidence sources answers a different question. A parser specification can explain why a line became part of a paragraph. A host manual can explain how a relative link is resolved. The settings in your build can establish which extension is enabled. A rendered page can show whether the instruction reached a reader. If the public guide shows the wrong default, collect the evidence from the layer where the value first changed. That often leads to a much smaller repair than rewriting the whole page.

The table that passes a visual check and loses the warning

Consider a two-column reference table headed Setting and Default. An editor adds a condition in a third cell in just one row. The raw line now reads | retries | 2 | after the initial request |. It is easy for a reviewer looking at the source to read all three values and approve the change.

GFM section 4.10 documents two quite different outcomes. In example 203, the header and delimiter have different cell counts, so the example does not become a table. In example 204, the header and delimiter agree. A short body row gains an empty cell and a longer body row loses its excess. Applied to our fictional row, the qualifying phrase would fall outside the two-column table. That prediction follows the published rule. We did not sample live repository pages. GFM examples 203 and 204

Check on the rendered guideWhat it establishesWhat it misses
A table existsThe content has table structureA body value might be missing
Headers read Setting and DefaultThe headings survivedA fact may sit under the wrong heading
The retries row reads 2The numeric default survivedWhat the number counts
The reader can state the maximum number of requestsThe qualifying rule can be recoveredWhether another version uses a different rule

There are two reasonable repairs. Add a Scope column, including the matching delimiter and a value for each relevant row, if scope varies by setting. Or put the rule directly above the table if it applies to the entire guide. For the fixture, we would choose the second. The rule is important enough to state once in a full sentence, and the table remains easy to scan. A duplicated sentence in every row would give editors several places to update when the retry policy changes.

Change the review question accordingly. Ask an editor to read the rendered guide, state the maximum and point to the words that justify the answer. The number alone is a poor assertion: an unrelated example on the same page might also contain a three. For a primer on writing the table itself, see the Markdown table guide.

Which version, file and section does a link actually open?

A repository path carries context that can disappear at publication. GitHub documents relative links and image paths in rendered files, with resolution based on the file and branch being viewed. It also documents a numeric suffix for repeated heading anchors. Renaming a section or inserting a second heading with the same wording deserves a navigation check even if the visible title looks familiar. GitHub writing syntax

MkDocs describes a different publishing operation. A relative link to another documentation source file can be rewritten to the appropriate HTML page at build time. The path can change while the section fragment stays intact. The guide separately explains that generated heading IDs depend on the table-of-contents extension and its settings. MkDocs internal links

Pandoc provides another useful illustration. Its manual shows a default identifier for a numbered heading and describes a separate option for GitHub-style identifiers. In its example, the default identifier for “3. Applications” is applications. A reader who sees the same heading text in two outputs cannot infer the destination ID from appearances alone. Pandoc heading identifiers

For the retry exercise, put a recovery link in the setup page. The destination is a sibling guide in the same version. Give the recovery guide sections for temporary errors and permanent errors. Start from the repository release tag and follow the link. Then start from the public versioned setup page and repeat. Record the visible product version, destination heading and first instruction under it. A successful response from a generic recovery page is insufficient evidence if it quietly routes the reader to the latest release.

Now edit the fixture by inserting a similarly named heading before the target. Follow the original link again. The interesting failure is a link that still lands somewhere plausible, possibly on the wrong recovery procedure. The repair might be a distinct heading, a supported explicit identifier or a maintained mapping for the public route. Choose the least complicated option both destinations can honor. An explicit identifier expressed in a host-specific syntax belongs in the agreement too.

What must survive when a reader copies an example?

The CommonMark fence rules treat the contents of a fenced code block as literal text. A language label after an opening fence can identify the example, but the specification does not prescribe one treatment for that label. GitHub separately documents how authors can show a triple-backtick fence inside a larger fence. That is useful when your guide teaches someone to write documentation itself. CommonMark fenced code GitHub code examples

Use a settings example whose meaning is unambiguous. In the fictional guide, the source line is max_retries = 2. Put the explanation about three total requests outside the code block. Copy the example from each supported destination into a plain text field and compare it with the intended line. For this one-line fixture, ignore a terminal newline and require every other character, including spaces, to match. If a destination offers a copy button, use it. If it relies on text selection, test selection. The acceptance condition concerns the text the reader gets, so the two sites can provide different controls.

Include a second example that contains punctuation your team actually publishes. A regular expression, a template variable or a shell pipeline exercises different characters from a single integer. For a guide about writing Markdown, include the closing fence as part of what the reader must copy. Verify where the example ends and where the explanation resumes. A code block extending through the next paragraph is easy to miss in a long page when both are still legible.

Keep these checks separate from execution. For a real product, validate the example against a named version in an isolated test environment. Save the expected value and a harmless result that confirms the setting took effect. This article’s invented setting is suitable for a rendering fixture only. The companion research on API documentation testing covers the separate question of whether an example still works with the software.

When is an extension worth its portability cost?

Suppose support wants a language switcher showing a command for each SDK. A site that knows how to render the component can keep the page concise. A repository reader still needs a labeled command they can use. The design decision is whether both audiences need the same interaction or just the same answer.

MDX allows components, expressions and imports in a document. Its documentation also identifies differences from ordinary Markdown: indented code has different behavior, and features such as GFM or frontmatter can require plugins. For a guide that uses components, include their definitions and applicable configuration in the inventory. Copying the prose file alone does not supply an imported component. MDX syntax and differences

Feature in the sourcePractical choiceAcceptance question
Parameter reference shared by both editionsRetain a table when both renderers support itCan both readers recover the same field, unit and constraint?
Interactive language switcherProvide labeled static examples where the control is unavailableIs every supported language discoverable in that edition?
Value imported from release metadataProduce static text for the repository edition from the same release dataDoes the older edition retain its original default?
Diagram available only on the websiteKeep a textual account of the essential steps in the shared guideCan the repository reader still complete the procedure?

The case for keeping a rich feature gets stronger when it saves real maintenance or helps a reader do something important. A generated defaults table can keep dozens of values aligned with the product. Removing the generation step might create a new burden for an editor. Instead, keep the authoritative data, generate an ordinary table for the simpler edition and record which release produced it. Test a changed value and a removed value, since stale rows can look entirely legitimate.

The case gets weaker when an extension adds presentation but makes essential meaning depend on one renderer. A custom warning box is fine if the warning also reads clearly in the repository. If the only copy of the warning is a property of the component, decide explicitly how that text reaches the second destination. Give the fallback an owner and a retest step. An unowned fallback is another copy of the guide someone can forget.

Run the retry guide as a release exercise

Use a small directory that a reviewer can understand without the rest of your documentation. The proposed fixture has a setup page, a recovery page and a diagram. Put it under a release-specific directory so that a link accidentally pointing to the newest version will be visible. Give the older and newer versions distinguishable answers. If both have the same default, a broken version link can pass every content check by coincidence.

Start the setup page with the product version and the sentence explaining that two retries follow the initial attempt. Add the settings line, the two-column table and a recovery link to a named section. Put the diagram under a nested asset directory. Label its purpose in the text. Keep an ordinary copy of each example available to the repository reader. Build the website using its normal production configuration and review the repository edition at the same revision.

Give the reviewer these tasks before showing them the expected answers:

  1. Starting from the release’s setup page, state the maximum number of requests and explain how you got it.
  2. Copy the setting into a plain text field. Record the exact key, value and any characters added by the presentation.
  3. Follow the recovery link. Record which release and which kind of error the destination describes.
  4. Locate the diagram and explain the step it illustrates. Open the page from its published subdirectory as well as from the repository.
  5. Repeat from the newer release. Use the intentionally different default to verify the version boundary.

Next, make a deliberate defect in a disposable copy of the fixture. Add a third value to the two-column table or point the recovery link to a similarly titled section in the wrong release. Run the checks again. A procedure that reports success for this known defect needs a better assertion. Restore the correct fixture before using it as the baseline. This is a proposed calibration step for a team’s own test, not a defect we observed in a product.

Save a small record for each destination: source revision, renderer and plugins, version shown, expected answer, actual answer and the first place the two diverge. Use words for the discrepancy. “Scope sentence missing from retry row” tells the author what to examine. “Snapshot changed” leaves them to reverse-engineer the intended behavior. Keep screenshots for differences that are hard to describe, such as an illustration cropped inside a narrow reference panel.

Fix the first thing that changed meaning

If a check fails, reproduce the smallest useful example and work outward. For a missing table condition, look at the source row, the interpreted cells, the HTML and the visible page. If the source has an extra cell and the expected GFM rule drops it, correcting the table addresses the cause. If all the text reaches the HTML but part is hidden on a narrow screen, changing authoring syntax would solve a different problem. For the retry exercise those two defects require the same retest: read the row and explain the request limit.

For a wrong recovery destination, record the source link, the emitted link, the visible route and the heading reached. A source file might be correct while a generator points at an old output directory. A correct page path might carry an obsolete fragment. A valid fragment might refer to a duplicate heading. That sequence helps separate the repair owned by the content author from the repair owned by the build maintainer. For a larger move, use the documentation migration checklist to cover existing public URLs beyond the shared-source fixture.

For a component that works only on the website, ask whether the static edition contains an equivalent instruction. If it does, document the intentional difference and continue. If it does not, choose between moving essential text into shared prose, generating a static edition or formally narrowing the supported destinations. The last choice can be appropriate for a guide whose purpose is an interactive exercise. Tell readers where they can complete it and give them enough context to choose that route.

Finally, keep the fixture small enough that someone will actually run it after a renderer upgrade. A changed link resolver should trigger the version and section checks. A syntax-highlighting change should trigger the copy checks. A component upgrade should trigger the static fallback check. Add a case when a real report exposes a gap. Retire cases when their feature or destination is no longer supported. The agreement earns its place when an editor can use it to decide whether today’s change is safe to publish.

Limitations

The counts describe examples in one pinned specification. The GFM examples describe formal rules, while the product manuals describe behavior in their stated contexts. Repository settings, generator versions and plugins can change an actual result. The retry guide is a fictional teaching example. The acceptance steps are proposed checks that a team can run on its own builds. This synthesis provides no vendor ranking, observed failure rate or measured effect on readers.

Sources

  1. CommonMark specification, version 0.31.2John MacFarlane · Accessed 2026-11-03
  2. CommonMark 0.31.2 example corpus (JSON)CommonMark · Accessed 2026-11-03
  3. GitHub Flavored Markdown specification, version 0.29-gfmGitHub · Accessed 2026-11-03
  4. Basic writing and formatting syntaxGitHub Docs · Accessed 2026-11-03
  5. What is MDX?MDX · Accessed 2026-11-03
  6. Pandoc User’s Guide, heading identifiersPandoc · Accessed 2026-11-03
  7. Creating and highlighting code blocksGitHub Docs · Accessed 2026-11-03
  8. RFC 7763, The text/markdown Media TypeRFC Editor · Accessed 2026-11-03
  9. Writing your docs, internal links and mediaMkDocs · Accessed 2026-11-03