Markdown flavors: CommonMark, GFM, and the variants in between

3 min read

“Markdown” is plural — there are several specs and many extensions. This article surveys the main flavors and the diff that bites you when porting between them.

Why flavors emerged

The original Markdown (John Gruber, 2004) was loosely specified, so implementations diverged:

  • No defined table syntax.
  • Nested-list rules varied.
  • Hard-break (<br>) handling was implementation-dependent.

CommonMark unified the core; GFM and others added features.

CommonMark — the standard

CommonMark is a strict specification. Most modern Markdown tooling targets it:

  • Nested lists, blockquotes, code blocks have well-defined behavior.
  • No tables, task lists, or strikethrough — those are extensions.
  • Implementations: pandoc, commonmark.js, cmark…

CommonMark alone lacks several “modern Markdown” niceties.

GitHub Flavored Markdown (GFM)

The GitHub dialect — CommonMark + extensions:

Extensions

| Col 1 | Col 2 |
| ----- | ----- |
| a     | b     |

- [x] done
- [ ] todo

~~strikethrough~~

https://example.com (autolink)

Notable additions

  • Tables — pipes and dashes.
  • Task lists[ ] [x].
  • Strikethrough~~text~~.
  • Autolinks — bare http://... becomes a link.
  • Emoji shortcodes:smile: → 😄.

GitHub, GitLab, Bitbucket, and most doc platforms target GFM.

MDX

JSX inside Markdown — embed React components directly:

import Chart from './Chart';

# Data viz

<Chart data={[1, 2, 3]} />
  • Used by Docusaurus, Next.js, Astro.
  • Good for interactive docs.

mdsvex (Svelte’s MDX)

Embeds Svelte components in Markdown:

<script>
  import Counter from './Counter.svelte';
</script>

# Heading

<Counter />

Common in SvelteKit doc sites.

Pandoc Markdown

Pandoc’s own flavor:

  • LaTeX math.
  • Bibliography / citations.
  • Table captions.
  • Definition lists.
  • Custom headers / footers.

Powerful for academic and book publishing — but it’s not a strict superset of GFM.

Obsidian / Bear

Note-app extensions:

  • Wiki links[[NoteName]]
  • Tags#tag
  • Highlights==important==
  • Image embeds![[image.png]]

None of these are GFM or CommonMark.

Common compat traps

Hard line breaks

CommonMark — two trailing spaces:

Hello␣␣
World

GFM has a “soft break renders as <br>” mode in some surfaces (GitHub Issues / PRs) but not in regular READMEs.

Lists and adjacent paragraphs

- list item

This is a paragraph

CommonMark — paragraph is outside the list. Some tools — treats it as a list-item continuation.

Ordered list start number

3. third
4. fourth

CommonMark — starts at 3. Old implementations — silently reset to 1.

HTML inside code blocks

```

<div>
```

Most flavors render the <div> literally (no HTML interpretation). Older implementations sometimes confuse it.

Table limits

GFM tables are constrained:

  • No multi-line cells — fake it with <br> or avoid.
  • No row spans / col spans.
  • Easy to misalign — columns of different widths look bad in source.

For complex tables, drop to HTML:

<table>
	<tr>
		<td>multi<br />line</td>
	</tr>
</table>

Math

CommonMark has no math. Extensions:

  • GFM — KaTeX ($...$ and $$...$$ on GitHub).
  • Pandoc — LaTeX math.
  • MDX — KaTeX / MathJax components.
Inline: $E = mc^2$

Block:

$$
int_a^b f(x) dx
$$

Heading anchors

Headings get auto-generated anchor IDs:

## My section

[link](#my-section)

Slug rules vary by tool:

  • GFM — lowercase, spaces → hyphens, strip punctuation.
  • Some tools — transliterate non-ASCII or drop it.

Cross-site link breakage usually traces back to slug differences.

Escaping

Backslash to keep * _ literal:

*not bold*

GFM extends escapes to ~ < > etc.

Summary

  • CommonMark is the standard, GFM is the de-facto.
  • Tool-specific extensions (MDX, Obsidian, Zenn) reduce portability.
  • Tables, math, and hard breaks are the most divergent.
  • For maximum portability, stick to GFM.

To preview Markdown rendering and check formatting, the markdown preview tool on this site shows the GFM rendering.