gfmgithubsyntax

GitHub Flavored Markdown (GFM) Explained

What GitHub Flavored Markdown adds on top of standard Markdown: tables, task lists, autolinks, strikethrough, emoji, and platform-specific features. With examples you can use today.

By mdkit Team··8 min read

"Markdown" is not one thing. There's CommonMark (the formal specification), and there's everything people informally call "Markdown" — which in 2026 almost always means GitHub Flavored Markdown (GFM).

If you write README files, issue comments, or documentation, you're writing GFM whether you know it or not. This post covers every GFM extension: what it does, how to write it, and where it does and doesn't work.

What GFM adds on top of CommonMark

GFM is a strict superset of CommonMark. Any valid CommonMark document renders identically in GFM. GFM adds:

  1. Tables
  2. Task lists
  3. Strikethrough
  4. Autolinks
  5. Disallowed raw HTML (security)
  6. Better handling of multi-line list items

Plus GitHub.com adds some platform-specific rendering (emoji shortcodes, @mentions, issue linking, Mermaid diagrams) that isn't strictly in the GFM spec but travels with it.

Let's go through each.

1. Tables

Pipe-separated tables with an alignment row:

| Name | Role | Score | | :------ | :-----: | ----: | | Alice | Admin | 100 | | Bob | Editor | 85 | | Charlie | Viewer | 42 |

Renders as:

NameRoleScore
AliceAdmin100
BobEditor85
CharlieViewer42

Alignment is set by the colons in the second row:

  • :--- → left
  • :---: → center
  • ---: → right
  • --- → default (usually left)

Tips:

  • You don't need to align the pipes visually — most editors do it for you.
  • Don't try to nest tables. Markdown doesn't support it. Use HTML if you absolutely must.
  • Tables can contain inline Markdown: links, bold, code, images.
  • Tables cannot contain: block-level elements (paragraphs, lists, code blocks). Keep it simple.

If manually typing tables is painful, use our Markdown Table Generator.

2. Task lists

Unordered list items with a checkbox:

- [x] Write the README - [ ] Add CI pipeline - [ ] Publish to npm

Renders with interactive-looking checkboxes. On GitHub.com issue comments, they become actually interactive — you can click to toggle.

Notes:

  • A lowercase x between brackets means checked. [X] (uppercase) also works on GitHub but isn't spec.
  • You can't have an unchecked state with anything other than a space between the brackets: [ ].
  • Task lists can be nested.
  • Great for README roadmaps, PR descriptions ("Acceptance criteria"), and issue templates.

3. Strikethrough

~~This text is struck through.~~

Renders as: This text is struck through.

One tilde (~text~) does not work in GFM — you need two. This distinguishes GFM from some other Markdown dialects where single-tilde is valid.

Naked URLs become clickable links:

Visit https://mdkit.io for free tools. Contact us at [email protected].

CommonMark requires you to wrap URLs in angle brackets: <https://example.com>. GFM auto-detects bare URLs and email addresses.

This is extremely convenient in issue comments and quick notes.

5. Disallowed raw HTML

GFM sanitizes certain HTML tags that would be security risks:

  • <script>
  • <style> (in some contexts)
  • <iframe> (restricted)
  • Event handlers like onclick=

Other tags pass through. This is why you can safely render user-submitted Markdown in a GFM renderer without worrying about XSS (mostly — always use a sanitizer in production).

6. Multi-line list items

CommonMark requires explicit 4-space indentation to continue a list item across lines. GFM is more forgiving:

- First item continues on this line without 4-space indent - Second item

In CommonMark, the second line would become a new paragraph. In GFM, it stays part of the same list item.

GitHub.com-specific extras

These aren't strictly GFM, but they work when your Markdown is rendered on GitHub.

Emoji shortcodes

:rocket: :heart: :sparkles: :+1:

Renders as: 🚀 ❤️ ✨ 👍

Full list: github.com/ikatyang/emoji-cheat-sheet.

Works on: GitHub.com, GitLab, Mattermost, some chat apps.
Does not work on: raw CommonMark renderers (unless you add an emoji plugin like remark-emoji).

@mentions

@octocat please review this PR.

Links to user profiles on GitHub. Behavior varies elsewhere.

Issue and PR references

Fixes #42. See also user/repo#101.

Auto-linked to the issue or PR on GitHub.

Commit SHAs

See a5c3785 for the fix.

GitHub auto-links 7–40 character hex strings to commits.

Mermaid diagrams

```mermaid graph LR A[Idea] --> B[PRD] B --> C[Design] C --> D[Ship] ```

GitHub renders Mermaid blocks as actual diagrams. So do GitLab, Obsidian, and Notion. Plain CommonMark shows them as code blocks.

Math

Inline math: $E = mc^2$ Block math: $$ \sum_{i=1}^{n} i = \frac{n(n+1)}{2} $$

GitHub uses KaTeX. Obsidian, Notion, and most static site generators with a math plugin support this too.

GitHub-specific alerts

GitHub introduced alert blocks in 2024, now part of GFM rendering:

> [!NOTE] > Highlights information users should know. > [!TIP] > Optional, but helpful advice. > [!IMPORTANT] > Crucial information. > [!WARNING] > Urgent; needs attention. > [!CAUTION] > Negative consequences of an action.

Works on GitHub.com. Not universally supported elsewhere (yet).

Where GFM renders correctly

PlatformGFM support
GitHub.com✅ Full (reference renderer)
GitLab✅ Near-full
Bitbucket✅ Most features
VS Code preview✅ With default extensions
Obsidian✅ Near-full
Notion⚠️ Partial (no autolinks)
Typora✅ Full
npmjs.com (README)✅ Most features
PyPI (README)⚠️ Needs GFM content type
Discord⚠️ Subset (no tables)
Slack⚠️ Subset (no tables, no task lists)
Reddit⚠️ Subset
Static site generators✅ With remark-gfm plugin

If you're targeting maximum compatibility, stick to CommonMark core. If you're targeting GitHub and modern tools, GFM is safe.

How to enable GFM in your toolchain

Marked (JavaScript)

import { marked } from "marked"; marked.use({ gfm: true, breaks: false }); const html = marked.parse(markdownText);

remark / rehype (unified ecosystem)

npm install remark remark-gfm remark-rehype rehype-stringify
import { unified } from "unified"; import remarkParse from "remark-parse"; import remarkGfm from "remark-gfm"; import remarkRehype from "remark-rehype"; import rehypeStringify from "rehype-stringify"; const html = await unified() .use(remarkParse) .use(remarkGfm) .use(remarkRehype) .use(rehypeStringify) .process(markdownText);

Markdown-it (JavaScript)

import MarkdownIt from "markdown-it"; const md = new MarkdownIt({ html: true, linkify: true }); // Tables, autolinks, etc. are on by default. // Task lists need markdown-it-task-lists plugin.

Pandoc

pandoc input.md -o output.html --from=gfm

Python (mistune, markdown-it-py)

from markdown_it import MarkdownIt md = MarkdownIt("gfm-like").enable("table").enable("strikethrough") html = md.render(markdown_text)

Practical gotchas

Check the URL: `https://example.com`

Inside backticks, autolinking is disabled (as it should be). Don't try to put links inside code spans.

Tables and line wrapping

Long table cells force wide horizontal scrolling on mobile. Consider splitting into multiple tables or using a definition list (HTML) for complex data.

Task list persistence

GitHub persists task list state when you edit the Markdown — but only in issues, PRs, and comments. In README files, toggling a checkbox doesn't save automatically (it opens the editor).

Nested lists in tables

| Feature | Notes | | :------ | :-------------- | | Auth | - OAuth<br>- JWT |

Lists inside table cells don't work in GFM. The workaround is <br> tags for line breaks, or structuring your content differently (use an H3 plus a list under the table).

Blockquote + list interaction

> Here's a quote: > - item one > - item two

Works. But forget the leading > on a continuation line and the rendering falls apart. Be consistent.

Summary

  • GFM = CommonMark + tables, task lists, strikethrough, autolinks, better list handling.
  • Enabled by default in most modern Markdown tools targeting technical content.
  • Add remark-gfm (or equivalent) to any static site generator that doesn't enable it by default.
  • Stick to GFM core for maximum portability; reserve GitHub-specific features (emoji, @mentions, alerts) for content that will only be rendered on GitHub.

You now know exactly what GFM adds and where it works. For a full syntax refresher, see our Markdown Cheat Sheet. For tables specifically, read Markdown Tables: syntax, alignment, and generators.

Frequently Asked Questions

Is GFM a separate language from Markdown?+
No. GFM is a superset of CommonMark, which is the standardized core of Markdown. Every valid CommonMark document is also valid GFM. GFM adds features on top — tables, task lists, strikethrough, autolinks, and a few GitHub-specific behaviors.
Where is GFM supported outside GitHub?+
Almost everywhere: GitLab, Bitbucket, VS Code preview, Obsidian, Notion, Typora, Discord (partial), Slack (partial), Reddit (partial), and most static site generators via the remark-gfm plugin. It's effectively the de facto modern Markdown standard.
What's the difference between GFM and CommonMark?+
CommonMark specifies the core syntax: headings, lists, paragraphs, links, images, emphasis, code. GFM adds tables, task lists, strikethrough, autolinks, disallowed-raw-HTML rules, and better handling of multi-paragraph list items.
Can I use GFM in a README on npm or PyPI?+
Partially. npm's README rendering follows GFM closely (tables, task lists, code blocks all work). PyPI uses CommonMark by default — tables and task lists render as plain text unless the package is configured to use GFM via the long_description_content_type and rendering metadata.
Are GitHub emoji shortcodes part of GFM?+
Emoji like :rocket: are a GitHub rendering feature, not part of the formal GFM spec. They work on GitHub.com, and most renderers that target GitHub (VS Code preview, many static site plugins) also support them, but they're technically a separate extension.

Keep reading