Reference

Markdown Syntax: A Complete Reference and Brief History

Published July 30, 2026

Markdown is simple enough to learn in an afternoon and fragmented enough that the same document renders differently in three tools. This reference covers the syntax that works everywhere, the extensions that mostly work, and the history that explains why the situation is like this.

Core syntax

These elements come from the original 2004 specification and work in every implementation.

Headings

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

Six levels. An alternative “setext” style exists for the first two:

Heading 1
=========

Heading 2
---------

Prefer the # form — it scales to six levels, is unambiguous, and does not depend on the line below.

Leave a blank line before and after a heading. Some parsers accept a heading immediately after text; CommonMark requires the blank line before it in certain contexts, and being consistent avoids the question.

Emphasis

*italic* or _italic_
**bold** or __bold__
***bold italic***

Asterisks are safer than underscores. Underscores inside words are not treated as emphasis in CommonMark (snake_case_name stays literal), but the rules differ between parsers. Asterisks behave consistently.

Paragraphs and line breaks

A blank line separates paragraphs. A single newline is collapsed into a space:

This line and
this line become one paragraph.

This is a second paragraph.

That collapsing is what makes the one-sentence-per-line writing style possible — see the long-form guide.

For a hard break within a paragraph, end the line with two spaces:

First line of an address··
Second line

Trailing whitespace as syntax is widely considered Markdown’s worst design decision — it is invisible, editors strip it, and diffs do not show it. <br> is the readable alternative and works everywhere. If you use trailing spaces, exempt Markdown from trailing-whitespace trimming in your editor.

Lists

- Unordered item
- Another item
  - Nested item, two-space indent
    - Deeper still

* Asterisks also work
+ As do plus signs

1. Ordered item
2. Second item
1. Also renders as 3 — the numbers are not read

Only the first number matters; the rest are renumbered sequentially. Writing 1. for every item means inserting an item does not produce a diff on every line below it — a real benefit in version control.

Nesting indentation is contested. Two spaces works in most parsers; four is safest for ordered lists, since a list item’s content block starts after the marker. When in doubt, use four spaces for nesting inside ordered lists and two inside unordered.

For multi-paragraph list items, indent the continuation:

1. First step.

    A second paragraph belonging to step one.

2. Second step.
[Inline link](https://example.com)
[With a title](https://example.com "Hover text")
[Reference link][ref]
[Implicit reference][]
<https://example.com>

[ref]: https://example.com
[Implicit reference]: https://example.com

Reference links keep prose readable when URLs are long, and let you reuse a URL. Definitions can go anywhere; the end of the document is conventional.

Angle-bracket autolinks (<https://example.com>) are the only reliable way to make a bare URL a link — plain URLs are linkified by GFM and not by strict CommonMark.

Images

![Alt text](image.png)
![Alt text](image.png "Title")
![Reference style][img]

[img]: diagrams/architecture.svg

Identical to link syntax with a leading !. Alt text is for assistive technology and should describe the image’s content; it is not a caption. For a visible caption you need HTML — see the images guide.

Code

Inline code uses backticks:

Run `npm install` first.

To include a literal backtick, use more backticks as the delimiter:

``Use `code` like this``

Fenced blocks with an optional language for highlighting:

```python
def convert(source: str) -> bytes:
    return render(parse(source))
```

To show a fenced block containing a fence, use more backticks on the outer fence — four outside, three inside. That is how the example above is written.

Indented code blocks (four spaces) are the original syntax and still work, but fenced blocks support language hints and are unambiguous. Use fences.

Blockquotes

> A quoted paragraph.
>
> A second paragraph in the same quote.
>
> > A nested quote.

The > is needed on blank lines between paragraphs, or the quote ends.

Horizontal rules

---
***
___

Three or more of the same character. --- is conventional — with the caveat that --- at the very top of a file is YAML frontmatter, and --- directly under a line of text is a setext h2. Leave a blank line above it.

Escaping

Backslash-escape any character with syntactic meaning:

\*not italic\*
\# not a heading
\[not a link\]
100\% complete

Inline HTML

Markdown permits raw HTML by design:

This is <em>emphasised</em> and this is <strong>strong</strong>.

<div class="callout">

**Note:** Markdown inside a block-level HTML element needs the blank lines
above and below to be processed as Markdown.

</div>

Those blank lines are essential and catch everyone. Without them the parser treats the whole block as raw HTML and your Markdown renders as literal characters. This is the single most common confusion when using div wrappers for styling.

Note that many parsers disable HTML by default for security (markdown-it’s html: false), so raw HTML is not universally available.

GitHub Flavored Markdown

GFM is a formal superset of CommonMark and effectively the de facto standard — most tools implement at least part of it.

Tables

| Left | Centre | Right |
| :--- | :----: | ----: |
| a | b | c |
| longer cell | x | 1.00 |

The alignment row is required. Colons set alignment: left, centre, right. Pipes do not need to line up in source — only the structure matters — though aligning them makes source readable.

Tables cannot contain block elements. No lists, no fenced code blocks, no paragraphs inside a cell. Inline code, emphasis and links work. For anything more complex you need an HTML table.

Escape a literal pipe inside a cell as \|.

Task lists

- [ ] Not done
- [x] Done
- [X] Also done

Renders as checkboxes. In a PDF they render as boxes that can be ticked by hand — see the team documentation guide for styling them for print.

Strikethrough

~~deleted text~~

Single tildes (~text~) work in some parsers and not in GFM. Use two.

GFM linkifies bare URLs and email addresses:

Visit https://example.com or email hello@example.com

Convenient, and a real portability difference — strict CommonMark leaves these as plain text.

Footnotes

Here is a claim.[^1]

[^1]: And the supporting note.

Widely supported, though not part of core CommonMark. Numbering follows reference order, not definition order. Covered in depth in the academic writing guide.

Common extensions

Beyond GFM, these appear frequently but support varies.

Math

Inline math: $E = mc^2$

Display math:

$$
\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}
$$

Delimiters vary — some parsers use \(...\) and \[...\], some require $$ on its own lines. Rendered by KaTeX or MathJax.

Diagrams

```mermaid
graph LR
    A[Write] --> B[Render] --> C[PDF]
```

A fenced block with mermaid as the language, rendered by the Mermaid library.

Definition lists

Term
: Definition of the term

Another term
: Its definition

Supported by Pandoc, PHP Markdown Extra, and some others. Not GFM.

Frontmatter

---
title: "Document Title"
author: Jordan Rivera
date: 2026-01-08
tags: [markdown, reference]
---

YAML metadata at the very top. Not part of any Markdown spec — it is a convention that static site generators and Pandoc adopted. Parsers without support render it as a table or as literal text, which is why exported notes sometimes have a stray block at the top.

Callouts and admonitions

The most fragmented area. At least four competing syntaxes exist:

> [!NOTE]
> GitHub's alert syntax.

> [!WARNING]
> Also GitHub.

::: note
Pandoc fenced div syntax.
:::

!!! note "Title"
    Python-Markdown / MkDocs syntax.

None is portable. Pick based on your target renderer, or use an HTML div with a class, which at least fails gracefully.

Heading anchors

Most parsers generate an id on each heading so you can link to it. The algorithm is usually: lowercase, spaces to hyphens, punctuation removed.

## Setting Up Your Environment

Link to it: [see setup](#setting-up-your-environment)

“Usually” is doing work there — duplicate headings get numeric suffixes, and the handling of non-ASCII characters and emoji differs between implementations. Hand-written contents lists break silently for this reason; generate them.

Where Markdown came from

John Gruber released Markdown in March 2004, developed with input from Aaron Swartz. The goal, from the original spec, was that a Markdown document should be “publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.”

That is the design principle everything follows from. The syntax borrows from conventions people had already been using in plain-text email for decades: asterisks around words for emphasis, > for quoted replies, blank lines between paragraphs. Markdown did not invent a notation so much as formalise one that already existed.

The original release was a Perl script, Markdown.pl, plus a prose specification. Both choices mattered enormously for what happened next.

Why flavours diverged

The prose specification had genuine ambiguities. It did not define behaviour for many edge cases: nested lists with inconsistent indentation, emphasis spanning other markup, HTML blocks interrupted by Markdown, lists interrupted by other block elements. Markdown.pl had behaviour for these cases, but it was implementation detail rather than specified intent — and in some cases it was arguably buggy.

Implementers hitting an ambiguity had to choose. They chose differently. By around 2012 there were dozens of implementations agreeing on the common cases and disagreeing on the edges, and the same document could render three ways.

Meanwhile the base syntax lacked things people needed. No tables, no code fences with language hints, no footnotes, no strikethrough. Every implementation added its own.

The notable branches:

PHP Markdown Extra (2004, Michel Fortin) — the earliest significant extension set. Tables, definition lists, footnotes, abbreviations, and attribute blocks. Much of what later became standard appeared here first.

MultiMarkdown (2005, Fletcher Penney) — aimed at academic and long-form publishing. Citations, cross-references, metadata, math, and export to LaTeX. Considerably ahead of its time.

GitHub Flavored Markdown (2009) — became the most influential simply through reach. Fenced code blocks with syntax highlighting, tables, autolinking, task lists, strikethrough, and the notable decision to treat newlines in comments as hard breaks (because users kept being surprised when their line breaks vanished).

CommonMark (2014) — the standardisation effort. Jeff Atwood, John MacFarlane (author of Pandoc), and others produced a rigorous specification with an extensive test suite covering the ambiguous cases. It deliberately does not add features; it specifies precisely what the core syntax means.

CommonMark’s launch was contentious — it was initially announced as “Standard Markdown”, which Gruber objected to, and it was renamed. Gruber has never endorsed it. But it solved the real problem: there is now a specification precise enough that implementations agree, with 600-plus test cases to prove it.

GFM was subsequently redefined as a formal CommonMark superset, which is why the two are now largely compatible.

Pandoc’s Markdown — the most feature-rich dialect, with citations, numbered cross-references, footnotes, definition lists, fenced divs, raw LaTeX passthrough, and much more. It is a superset of CommonMark and, in practice, its own language. See the Pandoc comparison.

Where this leaves you

The fragmentation is genuinely better than it was. CommonMark plus GFM covers what most people need and is implemented consistently across most tooling. The remaining divergence is concentrated in the newer extensions — callouts especially — and in whether HTML is enabled.

Which flavour you are writing

Practical guidance for staying portable:

Safe everywhere: headings, emphasis, lists, links, images, fenced code blocks, blockquotes, horizontal rules, inline HTML (where enabled).

Safe in almost everything: tables, task lists, strikethrough, autolinks. These are GFM and near-universal now.

Check first: footnotes, math, definition lists, frontmatter, Mermaid. Widely available, not guaranteed.

Tool-specific — expect to convert: callouts and admonitions, wikilinks ([[link]]), block references, key:: value properties, transclusion syntax. See the note app export guide for handling these.

A portability checklist

  • Use # headings, not setext
  • Use * for emphasis, not _
  • Use <br> rather than two trailing spaces
  • Use fenced code blocks with an explicit language
  • Use 1. for every ordered list item
  • Use four spaces to nest inside ordered lists
  • Use angle brackets for bare URLs
  • Leave blank lines around block-level HTML
  • Avoid callout syntax unless you know the renderer

Testing your assumptions

Two things worth doing once. The CommonMark reference implementation shows what strict CommonMark makes of a snippet — useful for settling whether something is core syntax or an extension. And converting the same document through two different tools reveals your accidental dependencies faster than reading any specification.

Try it yourself

The editor here implements CommonMark plus GFM — tables, task lists, strikethrough, autolinks — with footnotes, KaTeX math and Mermaid diagrams on top. It is a reasonable place to test whether a piece of syntax is portable, since it renders the widely-supported set rather than a tool-specific dialect.

Related: print CSS for turning this into a document, and tables, math and diagrams for the rich elements in depth.

About this guide

Written and maintained by the developer of MarkdownToFile — the browser-based converter this site runs on. Techniques described here are tested against the engines named in the text (Chromium's print pipeline, Paged.js, WeasyPrint), and engine limitations are stated rather than glossed over. Corrections are welcome via the contact page; more about the project on the about page.

Try it yourself — free, no signup

Convert your Markdown to a polished PDF right in your browser.

Open the editor