Markdown Headings: Syntax, Levels and Linking to a Heading
By the MDConverter team · Updated · 3 min read
Quick answer
A Markdown heading is a line that starts with one to six # characters followed by a space: # is the largest (level 1), ###### the smallest (level 6). Most renderers also give every heading an automatic anchor, so you can link to it with [text](#heading-text). Use one level-1 heading as the title and nest the others in order — that outline powers tables of contents, Word's navigation pane and screen readers.
Heading syntax: # to ######
Put the # characters at the start of the line, then a space, then the text. The number of # characters is the level.
# Level 1 — page title
## Level 2 — section
### Level 3 — sub-section
#### Level 4
##### Level 5
###### Level 6Level 1 — page title
Level 2 — section
Level 3 — sub-section
Level 4
Level 5
Level 6
Trailing # characters are optional and ignored (## Section ## is the same as ## Section), and up to three spaces of indentation before the # are allowed.
The alternative syntax: underlined headings
Level 1 and 2 headings can also be written by underlining the text with = or -. This "setext" style comes from the original Markdown and is still valid, but most people use # because it works for all six levels.
Project title
=============
Section
-------Project title
Section
--- under ordinary text turns that text into a heading. Leave a blank line above --- when you mean a horizontal rule.Linking to a heading (anchor links)
GitHub, GitLab, VS Code, Obsidian, MkDocs and most site generators give every heading an ID you can link to. GitHub's rules, which most tools copy:
- Convert the heading text to lowercase.
- Replace spaces with hyphens.
- Remove punctuation (except hyphens and underscores) and any formatting.
- If two headings produce the same ID, add
-1,-2… to the later ones.
So ## Getting Started (v2) gets the anchor #getting-started-v2.
See [Getting started](#getting-started-v2) below.
Jump to [the FAQ](#faq) or open [setup in another file](docs/setup.md#install).See Getting started below.
Jump to the FAQ or open setup in another file.
[[setup#Install]] wiki-link syntax instead.Need a table of contents built from these anchors? The Markdown table of contents generator creates one from your headings in a click.
Custom heading IDs
Automatic anchors change when you edit the heading text, which breaks links. Two ways to keep a stable ID:
- Extended syntax
## Install {#install}— supported by Pandoc, MkDocs (attr_list), Hugo, Jekyll (kramdown) and Docusaurus, but not by GitHub. - An HTML anchor placed above the heading —
<a id="install"></a>— which works on GitHub and anywhere HTML is allowed.
Heading best practices
- One level-1 heading per document, used as the title. Many site generators already add the page title as an H1, in which case start at
##. - Do not skip levels (
##straight to####). Screen readers and tables of contents rely on the order. - Keep headings short and descriptive — they become anchor IDs, tab titles in some tools, and sheet names when you convert tables to Excel.
- Do not use headings for bold text. If you only want emphasis, use
**bold**. - Leave a blank line before and after a heading. Not always required, but some renderers need it and it keeps the source readable.
Headings when you convert Markdown
Headings carry real structure into other formats: Markdown to Word maps #–###### to Word's Heading 1–6 styles (so the navigation pane and automatic table of contents work), Markdown to PowerPoint starts a new slide at each top-level heading, and Markdown to HTML produces <h1>–<h6>. Going the other way, Word to Markdown turns Word heading styles back into # headings.
Heading support by app
| App | Supported | Notes |
|---|---|---|
| GitHub / GitLab | Yes | All six levels, automatic anchors (hover a heading to see the link icon). |
| Obsidian | Yes | All six levels; link with [[Note#Heading]]. |
| Notion | Partly | Typing #, ##, ### + space creates Heading 1–3; there are no levels 4–6. |
| Discord | Partly | #, ## and ### only; -# makes small subtext. |
| Yes | Markdown mode supports # headings. | |
| Slack | No | No headings in messages; use bold text. |
| Google Docs | Partly | With Markdown enabled, # + space at the start of a line becomes a heading. |
Common mistakes and how to fix them
| Problem | Fix |
|---|---|
#Heading shows the # symbol | Add a space after the # characters: # Heading. CommonMark requires it. |
Text above --- became a heading | Add a blank line between the text and the --- horizontal rule. |
| Anchor link does nothing | Check the ID rules: lowercase, hyphens for spaces, punctuation removed. Duplicate headings get -1, -2. |
| Heading inside a list item is not rendered | Indent it to the list item’s content, or move it out of the list. |
Tools for this
- Markdown TOC Generator A linked table of contents for a README or any Markdown file, with GitHub-exact anchors.
- Markdown to Word Convert Markdown to Word Documents (.docx) Online
- Markdown to PowerPoint Convert Markdown to PowerPoint Online (.pptx)
- Word to Markdown Convert Word Documents (.docx) to Clean Markdown
- Markdown to HTML Convert Markdown to Clean, Semantic HTML5
Frequently Asked Questions About Headings
Comprehensive answers to common technical, formatting, security, and compatibility questions.
Related reading
- Markdown Links: Every Way to Add a Link — Inline and reference links, links to headings and files, email links and new-tab links.
- Markdown Lists: Bullet Points, Numbered Lists and Nested Lists — Bullets, numbered lists, nesting, starting numbers and the indentation rules that trip people up.
- Markdown Text Formatting: Bold, Italic, Strikethrough and More — Bold, italic, strikethrough, underline, highlight, superscript and subscript — with app support.