If you write code, you write Markdown. READMEs, pull request descriptions, issue comments, documentation sites, Slack messages, Notion pages — it's everywhere. Yet plenty of developers never consciously learn it. They pick it up by osmosis and miss half the syntax.
Let's fix that.
Why Markdown Exists
John Gruber created Markdown in 2004 with a specific goal: make text-to-HTML conversion readable in its raw form. The HTML it produces should match what you'd expect from plain text conventions people already used in email.
A # at the start of a line becomes an <h1>. Wrap a word in **asterisks** and it's bold. It maps to what already feels natural. A Markdown file should be readable before it's rendered — that was the whole bet.
It paid off. Markdown is now more widely used than almost any document format that came after it.
Core Syntax
Headings
Headings use # characters. One # is <h1>, two ## is <h2>, up to six.
# Page Title
## Section
### Subsection
In technical writing, use ## as your top-level section heading within a document — reserve # for document titles.
Emphasis
**bold text**
*italic text*
***bold and italic***
~~strikethrough~~
Use **double asterisks** for bold, single asterisks or underscores for italic. The conventions are interchangeable, but pick one and stick to it — mixing them makes your raw files noisy.
Lists
Unordered lists use -, *, or + as markers. Ordered lists use numbers followed by a period.
- First item
- Second item
- Nested item (indent 2 spaces)
- Another nested item
1. Step one
2. Step two
3. Step three
For nested lists, indent by two spaces (or four, depending on the parser). This is one of those areas where parsers disagree, so two spaces is the safest default.
Links and Images
[Link text](https://example.com)
[Link with title](https://example.com "Hover title")


Reference-style links keep your prose readable when URLs are long:
Check out [the documentation][docs] for details.
[docs]: https://docs.example.com/getting-started
Code
Inline code uses single backticks: `variable_name` or `npm install`.
Fenced code blocks use triple backticks, with an optional language identifier for syntax highlighting:
```javascript
function greet(name) {
return `Hello, ${name}!`;
}
```
The language hint after the opening backticks (javascript, python, bash, json, etc.) is optional but highly recommended. GitHub, VS Code, and most renderers use it for syntax highlighting.
Blockquotes
> This is a blockquote.
> It can span multiple lines.
>
> And multiple paragraphs with a blank quoted line.
Tables
Tables are one of the most useful and least-used Markdown features:
| Method | Endpoint | Description |
|--------|---------------|--------------------|
| GET | /users | List all users |
| POST | /users | Create a user |
| DELETE | /users/:id | Delete a user |
The column separator lines must include at least one - per cell. In practice, using three or more dashes (---) is the safer convention, as some parsers require it. You can align columns with colons: |:------| for left, |------:| for right, |:-----:| for center.
CommonMark vs GitHub Flavored Markdown
"Markdown" is not one format. Gruber's original spec left many edge cases undefined, and every platform filled in the gaps differently.
CommonMark is the most rigorous attempt at a unified specification — comprehensive test suite, covers all the edge cases, basis for most modern parsers. If you're building a tool that renders Markdown, CommonMark is the target spec.
GitHub Flavored Markdown (GFM) is CommonMark plus extensions: tables, task lists, strikethrough, and autolinked URLs. GFM is what GitHub, GitLab, and most documentation tools use.
Other dialects include MultiMarkdown (footnotes, metadata), Pandoc Markdown (LaTeX integration, academic writing), and countless platform-specific extensions. They're all compatible at the base level but differ in the extras.
For daily developer use, assume GFM. It's the closest thing to a universal superset.
Task Lists and Footnotes
GFM adds task lists, which are genuinely useful in issue tracking and project docs:
## Release checklist
- [x] Update changelog
- [x] Bump version in package.json
- [ ] Tag the release
- [ ] Deploy to staging
- [ ] Announce on Slack
The rendered output shows actual checkboxes. On GitHub and GitLab, the checkboxes in issues and PRs are interactive.
Footnotes are less universal but supported by many extended dialects:
HTTP was designed for stateless communication.[^1]
[^1]: Fielding, R. (2000). Architectural Styles and the Design of Network-based Software Architectures.
Markdown in the Wild
You'll encounter Markdown in more places than just READMEs.
GitHub and GitLab render Markdown in README files, issues, pull requests, wikis, and commit messages. GFM is the dialect. The CONTRIBUTING.md and CODE_OF_CONDUCT.md files in most open source repos are Markdown.
Slack uses a simplified Markdown-like syntax for messages. Not full Markdown, but *bold*, `code`, and fenced code blocks work. It diverges from standard Markdown in ways that are occasionally annoying.
Notion supports Markdown shortcuts for formatting. Type ## followed by a space and Notion converts it to a heading in real time.
VS Code renders .md files with a preview pane (Cmd+Shift+V on Mac). It uses CommonMark with some GFM extensions. The editor also renders Markdown in hover documentation for code.
Documentation tools like MkDocs, Docusaurus, VitePress, and Jekyll all use Markdown as the source format. They usually support CommonMark plus their own extensions.
Tips for Readable Raw Markdown
The goal is for the plain text to be as readable as the rendered output. Some habits help:
Blank lines between elements. A blank line before and after headings, code blocks, and lists makes the raw file easier to scan. Some parsers require this; all parsers tolerate it.
Consistent list markers. Pick - for unordered lists and stick to it. Mixing - and * in the same document is valid Markdown but visually noisy.
Line length in prose. Some teams hard-wrap at 80 characters, others use one sentence per line (makes diffs cleaner). Both are fine; just pick one per project.
Descriptive link text. Write [the CommonMark spec](https://spec.commonmark.org/) not [click here](https://spec.commonmark.org/). Screen readers and grep both thank you.
Language hints on code blocks. Always add the language identifier. It costs one word and improves syntax highlighting everywhere your doc is rendered.
Checking Your Work
The YAML Explained post covers a similar "human-readable data format" angle if you're comparing serialization formats. And if you're curious about word counts or want to estimate read time while writing documentation, the Word Counter handles that — paste your Markdown text and it counts both raw and approximate rendered words.
For interactive rendering while you write, the Markdown Preview tool lets you paste any Markdown and see the rendered output instantly, including tables, code blocks, and task lists.
The authoritative reference for the CommonMark specification lives at spec.commonmark.org — it's exhaustive but also the definitive answer whenever two parsers disagree.
Wrapping Up
Markdown's power is that it's readable before it's rendered. That philosophy — the source should be the documentation — is why it's outlasted every "rich text" alternative that came after it. Learn the dozen syntax rules and you'll write better READMEs, cleaner issue descriptions, and documentation that survives copy-paste into any tool on your team's stack.