MD File Documentation


Summary

A Markdown (MD) file is a plain-text document that uses simple marks — # for headings, **bold**, - for lists, [text](url) for links — which a processor turns into HTML. John Gruber created Markdown in 2004; the CommonMark specification (2014) made it unambiguous, and GitHub Flavored Markdown adds tables and task lists. It is UTF-8 text with MIME type text/markdown, so any editor opens a .md file, while VS Code, Obsidian, or GitHub render it.

Technical details

FeatureValue
Full nameMarkdown Document
File extension.md, .markdown
MIME typetext/markdown (RFC 7763)
Format typeLightweight markup language (plain text)
Developed byJohn Gruber, with Aaron Swartz
Initial release2004
StandardisationCommonMark (2014); GitHub Flavored Markdown (GFM)
EncodingUTF-8 (recommended); may carry a BOM
Magic numberNone — identified by extension and syntax
Open standardYes
Heading syntaxATX (#######) or Setext (underlines)
Emphasis*italic*, **bold**, ~~strike~~ (GFM)
Lists- / * / + bullets, 1. ordered, - [ ] tasks (GFM)
CodeBacktick `inline` and fenced ``` blocks
TablesPipe-and-dash (GFM extension)
Front matterOptional YAML between --- fences (static-site generators)
Related extensions.markdown, .mdx, .mkd, .rmd, .txt
Specificationspec.commonmark.org
Syntax at a glance

Markdown is plain UTF-8 text with no signature or magic number. A leading # plus a space is an ATX heading (one to six # set the level); * or _ wrap emphasis (*em*, **strong**); a line starting with -, *, or + is a bullet, and 1. an ordered item. Links are [text](url), images ![alt](url). Code is a backtick span or a triple-backtick fenced block with an optional language hint. A block is separated from the next by a blank line. Some files open with a YAML front-matter block fenced by --- at offset 0.

What is a Markdown (MD) file?

Markdown is a lightweight markup language created in 2004 by John Gruber, with input from Aaron Swartz, to let people write formatted documents in readable plain text. The design goal was that the source stays legible as-is — a hash makes a heading, asterisks make emphasis, hyphens make a list — and a processor then converts that text to HTML. Because an .md file is nothing but UTF-8 text, it is tiny, editable in any program, and diff-friendly in version control, which is why it became the default for software documentation. Gruber shipped the original as a Perl script, Markdown.pl, that rewrote the marked-up text into HTML tags.

Markdown carries no signature, header, or magic number: a .md file is identified only by its extension and its conventional syntax. It may begin with a UTF-8 byte-order mark (EF BB BF) or a YAML front-matter fence, but neither is required. The rest of this article describes the actual block and inline grammar a parser applies, the difference between the loose original and the CommonMark specification, the GitHub extensions most people meet, and the two-phase way a processor turns the text into HTML.

Block structure and inline structure

Every Markdown parser works in two passes. It first splits the document into block-level structures — headings, paragraphs, lists, block quotes, code blocks, thematic breaks — then parses inline content (emphasis, links, code spans) inside the text of those blocks. The separator between blocks is the blank line: one or more blank lines end a paragraph and start the next block. This is why an accidental missing blank line is the most common Markdown rendering bug, joining two intended blocks into one.

Headings come in two styles. ATX headings use one to six leading # characters followed by a space, so # Title is an <h1> and ### Sub is an <h3>. Setext headings underline the text with = (level 1) or - (level 2) on the following line, which is why a line of dashes under a paragraph unexpectedly becomes a heading. Paragraphs are simply runs of text between blank lines. Block quotes prefix each line with >. A thematic break (horizontal rule) is three or more -, *, or _ on their own line.

Lists, code spans and fenced blocks

Lists are created with -, *, or + for bullets and 1. for ordered items; a parser treats the three bullet markers as equivalent, and it uses the number of the first ordered item as the start value, ignoring the rest. Nesting is by indentation, and getting that indentation wrong (mixing tabs and spaces, or under-indenting a child) is a frequent cause of broken output.

Code is represented two ways. An inline code span is wrapped in backticks, and you can use multiple backticks to include a literal backtick inside: ``a `b` c``. A block of code is either indented by four spaces or wrapped in a fenced block of three or more backticks (or tildes), with an optional language identifier after the opening fence that renderers use for syntax highlighting:

```javascript
console.log("Hello, world!");
```

The language token after the opening ``` (here javascript) is an info string: CommonMark passes it through as a class on the generated <code> element, and highlighters read it to choose a grammar. Fenced blocks are safer than indented ones because they need no whitespace counting and can contain blank lines.

An inline link is [visible text](https://example.com "optional title"), and an image is the same with a leading !: ![alt text](image.png). Markdown also supports reference-style links, where the destination is defined once elsewhere and referred to by label, which keeps long URLs out of the prose:

See the [spec][cm] for details.

[cm]: https://spec.commonmark.org/  "CommonMark"

The definition line ([cm]: ...) is a block that produces no output of its own; the parser collects all such definitions first, then resolves every [text][label] reference against them. Autolinks wrap a bare URL in angle brackets, <https://example.com>, and GFM additionally turns a plain https:// URL in running text into a link without any brackets at all.

CommonMark and GitHub Flavored Markdown

Gruber’s original description was loose, and a rendered-output test suite did not exist, so processors diverged on edge cases (how nested lists indent, when emphasis binds). CommonMark, published in 2014, is a strict, unambiguous specification with a reference implementation and a conformance test suite that pins down every one of those cases. It defines exactly the block and inline grammar described above.

GitHub Flavored Markdown (GFM) is a superset of CommonMark that adds the features most people now expect: pipe-and-dash tables, task-list items (- [ ] and - [x]), strikethrough with ~~text~~, and automatic linking of bare URLs. A GFM table uses pipes to separate cells and a dash row to mark the header, with colons in the dash row setting column alignment:

| Feature | Standard  |
|:--------|----------:|
| tables  | GFM       |
| tasks   | GFM       |
FeatureWhere it is defined
Headings, lists, emphasis, code, linksCommonMark (and original Markdown)
TablesGFM extension
Task lists (- [ ])GFM extension
Strikethrough (~~)GFM extension
Autolinked bare URLsGFM extension
YAML front matterStatic-site generators (not core)

YAML front matter and raw HTML

Static-site generators such as Jekyll, Hugo, and MkDocs let a file open with a front-matter block: a run of key: value pairs fenced by --- lines at the very top of the document, holding metadata like the title, date, and tags. It is not part of core Markdown — a plain CommonMark parser would render the fences as a thematic break and text — so the generator strips it before passing the body to the Markdown processor.

Markdown also permits raw HTML to be written directly in the source, and a compliant processor passes it through untouched. That is a feature (it lets you drop in a <table> or a <div> Markdown cannot express) and a hazard: because the source can contain <script> or event-handler attributes, a renderer that displays untrusted Markdown must sanitise the HTML output. Reputable renderers such as GitHub and VS Code strip active content; a naive one that emits the raw HTML verbatim would let a malicious .md file inject script into the page that displays it. The .md file itself is inert text and cannot execute anything on its own.

How a processor turns Markdown into HTML

Turning .md into a web page is the format’s native purpose. A processor parses the blocks and inlines into a document tree and then serialises that tree as HTML: # Title becomes <h1>Title</h1>, a fenced block becomes <pre><code>, a bullet list becomes <ul><li>. The same tree can be rendered to other targets: Pandoc reads Markdown into its internal document model and writes PDF (via a LaTeX engine), DOCX, EPUB, or HTML from it. This layering — parse once, serialise to many formats — is why the same README renders on GitHub, exports to PDF from an editor, and feeds a static-site build without being rewritten.

Frequently asked questions

What is a README.md file?

It is the front-page documentation of a code project, written in Markdown. GitHub, GitLab, and Bitbucket render the README.md in a repository’s root automatically on the project home page, using GitHub Flavored Markdown, so tables and task lists display as formatted output rather than raw marks.

Is Markdown the same as a plain text file?

Structurally yes — a .md file is plain UTF-8 text and you can rename it to .txt and it still opens. The difference is convention: the .md extension signals to editors and hosting platforms that the text should be parsed as Markdown and rendered, whereas a .txt is shown verbatim.

What is the difference between Markdown and GitHub Flavored Markdown?

GFM is a superset of the CommonMark standard. It keeps all of CommonMark’s syntax and adds tables, task lists, strikethrough, and automatic linking of bare URLs. Content written in plain CommonMark renders correctly under GFM; content using GFM tables or task lists may not render on a processor that only implements core CommonMark.

References