What Is Markdown

Most people first hear of Markdown and assume it is another word for a web page editor. This page is about correcting that impression. Markdown is not an editor, not a layout engine, and not a replacement for HTML. It is a set of rules for describing the structure of a document using plain text characters, and nothing else. In practice that means a handful of familiar symbols, such as #, *, -, [], and (), mark out headings, lists, emphasis, and links, so that the text stays readable on its own while remaining parsable into HTML. Once you see it that way, a pile of otherwise baffling observations becomes obvious: the same .md file can look different in GitHub, in VS Code, and in Obsidian and still be the same document, because the file records what the pieces mean and the renderer decides how they look. There is a second thing worth understanding early, and it is the reason this format survived while a dozen similar ideas faded. The Markdown source is not a program, not a database, and not an opaque export. It is a text file that you can open with any editor on any machine, read in a terminal, search with grep, and diff with diff, twenty years from now. Everything else on this page follows from that one property.

A Short History

Markdown was created in 2004 by John Gruber, with help from Aaron Swartz, and released in two parts: a syntax description and a Perl script called Markdown.pl that converted the syntax to HTML. The goal was modest and specific. Gruber wanted a way for people to write formatted content for the web without learning HTML and without giving up plain text as the source format. The original release was ambiguous by accident rather than by design, and that ambiguity turned into a decade of divergence. The syntax description did not settle questions such as how deeply a sublist must be indented, whether a blank line is required before a block quote, or when a list is loose enough that each item needs its own paragraph tag. Early implementers settled those questions by reading Markdown.pl itself, which was buggy, so different tools rendered the same document differently. By 2014 there were dozens of implementations in many languages and no single behaviour to point at.

That is the problem CommonMark set out to solve. Beginning in 2014, a group of maintainers including John MacFarlane, Jeff Atwood, and Martin Woodward wrote an unambiguous specification backed by a comprehensive test suite, so that any conforming parser produces the same output for the same input. The specification is still maintained and versioned; the current release is 0.31.2, published in January 2024, authored by John MacFarlane. CommonMark is now the shared baseline for a long list of adopters, including Discourse, GitHub, GitLab, Reddit, Stack Overflow, and Swift. On top of that baseline, GitHub defined GitHub Flavored Markdown, a strict superset of CommonMark. GFM adds tables, task lists, strikethrough, and automatic links, and it filters a small set of unsafe raw HTML tags. Its published specification is version 0.29-gfm, dated 2019-04-06. In practice GFM is the dialect most people meet, since it is what GitHub renders in READMEs, issues, and pull requests, and what most static site generators assume by default.

The Design Philosophy

Gruber’s own summary of the goal is the best description of the format ever written, and it is worth quoting because every later decision can be traced back to it:

The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.

Read that twice. “Publishable as-is, as plain text” is the load-bearing clause. It means the source is not an intermediate format to be compiled away; it is a legitimate form of the document in its own right. A reader with no Markdown tooling can open the file and understand it, which is why Markdown files survive being emailed, pasted into a chat window, or checked into a repository where nobody is around to render them. Three ideas follow from that goal.

Readability before precision. Where a choice existed between the terser encoding and the more obvious one, Markdown usually took the obvious one. A heading is a line that starts with a hash, not a tag with a closing counterpart, because the hash reads like a heading even to someone who has never seen the syntax. The cost is that Markdown is more verbose than HTML. The benefit is that the file is legible to a human without any decoding step.

Portability over features. The core language is deliberately small: headings, emphasis, lists, links, images, code, block quotes, and rules. Anything richer, such as tables, footnotes, or mathematical formulas, lives in an extension layer that a renderer may or may not implement. Markdown was never going to describe a printed page, and it does not try.

Plain text over everything. Because the source is plain text, it can be handled by tools that know nothing about document formats at all. grep finds the sentence you need, git diff shows what changed in the requirement, and a shell script can rewrite a heading across a hundred files. No special editor is required, and no vendor can take the format away.

One Source, Two Renderings

The clearest way to see what Markdown actually does is to put the same passage in both of its forms. Here is the source:

# Install Node.js

Run `npm install` in the terminal, then run `npm start`.

And here is the HTML that a parser produces from it:

<h1>Install Node.js</h1>
<p>Run <code>npm install</code> in the terminal, then run <code>npm start</code>.</p>

Read the two versions side by side and the division of labour is immediate. The source says what the text is: a level one heading, a paragraph, and two spans of code. The HTML says how it should be presented: which element to use, where to put it, and how to close it. You wrote the first one; the parser produced the second one. Nobody had to write a closing h1, because the parser knows that headings cannot nest. The same division shows up in inline formatting, where this source:

**Note**: read the [installation guide](https://example.com/install) first.

becomes:

<p><strong>Note</strong>: read the <a href="https://example.com/install">installation guide</a> first.</p>

The two asterisks become a strong element and the bracketed text becomes a link, but you never mention an element. You described which words matter and where the link goes; the parser chose the machinery.

One deliberate escape hatch remains: Markdown permits raw HTML and passes it through untouched. A document can mix the two:

This is a Markdown paragraph.

<div align="center">Here is a native HTML block.</div>
<p>This is a Markdown paragraph.</p>
<div align="center">Here is a native HTML block.</div>

The paragraph was parsed, and the div was left alone. This is genuinely useful for the occasional table layout or embedded comment, but it is also the single most common source of confusion, because it means “does this file contain HTML?” is not the same question as “is this file Markdown?”. The answer depends on which constructs carry the structure.

The Ecosystem

Every mainstream editor supports Markdown, but they do not all implement the same dialect. The differences come from which extensions each one enables on top of the core syntax:

DialectStatusWhat it adds beyond the core syntax
CommonMarkThe shared baselinePrecise rules for headings, lists, code, quotes, and emphasis
GFMThe GitHub extension of CommonMarkTables, task lists, strikethrough, automatic links
Platform dialectsPrivate to each vendorMath formulas, footnotes, callout blocks, diagrams, collapsible sections

This is why the same source can look right in one place and subtly wrong in another. A table renders in GitHub and turns into a row of pipes on a platform that never implemented the table extension. Nothing is broken; the two renderers simply speak different dialects, and the file is written in the larger of the two.

Common Pitfalls

Exercises

Three files are given below. Exactly one of them is written in Markdown. Identify the other two, state what format each of them actually is, and give the one-line reason for each answer.

  • notes.txt: a line reading Title, then a line reading Body, with no markup characters anywhere.
  • doc.md: a line reading # Title, a blank line, then a line reading Body.
  • page.html: a line reading <h1>Title</h1>, then a line reading <p>Body</p>.

Then write down the HTML that a parser produces for the file that is Markdown.

Markdown SyntaxFile FormatsPlain Text

Approach:

Decide what carries the structure of each file, rather than trusting the extension name. Markdown marks structure with typographic symbols: a hash for a heading, a dash for a list item, backticks for code. Plain text has no markers at all, and HTML carries its structure with element tags. Because Markdown allows raw HTML to be embedded, the presence of a tag somewhere in a .md file settles nothing on its own.

Steps:

  1. doc.md is Markdown. A hash followed by a space is a level one heading, and the blank line separates the heading from the paragraph that follows. That is ordinary Markdown.
  2. notes.txt is not Markdown. It is plain text, with no structure markers, so there is nothing for a parser to interpret. Plain text and Markdown are different things, and the extension name alone decides nothing.
  3. page.html is not Markdown. It is HTML source, and the structure is carried by the h1 and p tags. A .md file may legitimately contain those tags, but when the tags are what organise the whole document, the document is HTML.
  4. The rendered output of doc.md follows from the same rules: the heading becomes an h1 element and the body becomes a paragraph.

Answer:

Only doc.md is Markdown. notes.txt is plain text with no structure markers, and page.html is HTML whose structure is carried by element tags.

A parser turns doc.md into:

<h1>Title</h1>
<p>Body</p>

The tell is which characters carry the structure: symbols for Markdown, tags for HTML, and nothing at all for plain text.

Summary

You should now be able to say what Markdown specifies and, just as importantly, what it deliberately leaves unspecified. You should be able to place it in history, from the 2004 release of Markdown.pl through the CommonMark specification and the GFM dialect that most platforms actually implement, and explain why the readable-source goal drove nearly every design decision. You should also be able to read a Markdown file and predict the HTML it produces, and explain why the same file can render differently on two platforms without either renderer being wrong. The next page takes the practical side of the question: what you actually gain by choosing Markdown over a rich text editor.

Found an issue with this content?

Tell us what could be improved.