Markdown Headings

Markdown headings turn a wall of text into a scannable, navigable structure — the same # syntax works whether you're writing a README, a docs site, or a blog post that gets converted straight to HTML. This guide goes past basic # syntax into the parts most guides skip: custom anchor IDs, how different static site generators actually render headings, and how heading structure affects on-page SEO.

For the full syntax reference including compatibility across CommonMark and GFM, see Markdown Syntax. For a quick copy-paste version, use the Markdown Cheat Sheet.

💡 Practice as you read: Open the Markdown Editor for live preview.

Open EditorDownload PDF

What Are Markdown Headings?

A Markdown heading is created by prefixing text with one or more # characters — no font-size changes, no styling tags. Parsers convert # through ###### directly into HTML <h1>–<h6>.

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

Live Preview#

Live Preview

Heading 1#

Heading 2#

Heading 3#

Heading 4#

Heading 5#
Heading 6#

Two compatibility rules most guides skip:

  • Always leave one space after the #. Some parsers silently ignore ##Heading with no space — it just prints as plain text.
  • Leave a blank line before and after every heading. Most modern parsers tolerate missing blank lines, but stricter processors — and some Jekyll/Hugo setups — will merge the heading into the paragraph above it if you skip this.
Some paragraph text.

## Correct: blank line above and below

More paragraph text.

If you're brand new to Markdown, start with Markdown Basics first.

Heading Levels: What Each One Is Actually For

Level Syntax HTML Use it for
H1 # Heading <h1> The page/document title — one per document
H2 ## Heading <h2> Main sections
H3 ### Heading <h3> Subsections under an H2
H4 #### Heading <h4> Supporting detail under an H3
H5 ##### Heading <h5> Rare — deep technical references only
H6 ###### Heading <h6> Rarest — avoid unless the document genuinely needs 6 levels

Most README files and blog posts never need past H3. If you're reaching for H5/H6 regularly, that's usually a signal to split the document (see When to Split Large Documents), not to keep nesting.

ATX vs. Setext Headings

Style Syntax Levels supported Recommended
ATX # Heading H1–H6 ✅ Yes — use for all new documents
Setext Heading + === or --- on the next line H1–H2 only Only if maintaining legacy content
Project Title
=============

Installation
------------

= produces an H1, - produces an H2. Because Setext caps out at two levels, it can't represent real document hierarchy — treat it as legacy syntax, not a style choice.

Building a Logical Heading Structure

Treat headings as an outline, not a font-size picker — pick a level because of where the content sits in the document, never because a heading "looks right" on screen. If you want different visual styling without changing structure, that's a CSS/theme decision, not a heading-level decision.

# User Guide
## Getting Started
### Installation
### Configuration
## Features
### Authentication
### API Access
## Troubleshooting

Each H2 is a major topic; each H3 splits it further. Skipping levels (H2 straight to H4) is the most common hierarchy mistake — see Common Heading Mistakes.

When to Split Large Documents

If a document regularly reaches H5 or H6, it's usually doing too much in one page. Split it into linked pages instead — e.g., one monolithic API guide becomes separate pages for Authentication, Endpoints, and Error Codes, each with its own H1 and a shallow H2/H3 outline.

Preview your outline in the live editor before publishing, and link related pages through a Documentation Index.

Real-World Heading Examples

A project README:

# My Project
## Features
## Installation
## Quick Start
## Configuration
## Usage
## Contributing
## License

A technical API reference (deeper nesting, justified by content volume):

# API Documentation
## Authentication
### API Keys
### OAuth
## Endpoints
### Users
### Projects
### Billing

A blog post converted to HTML (SEO-driven structure — see next section):

# 10 Ways to Speed Up Your Website
## 1. Optimize Images
## 2. Enable Caching
## 3. Minify CSS and JavaScript

Notice the pattern: H1 count never exceeds one, and H2 count matches the number of real, distinct sections a reader would look for — not the number of paragraphs.

Headings and On-Page SEO

When Markdown compiles to HTML — for a blog, docs site, or CMS — headings stop being just visual structure and become on-page signals search engines use to parse the page.

  • Use exactly one H1 per page, matching the primary topic. HTML5's sectioning model technically permits multiple H1s, and some component-based frameworks generate them by accident — but a single H1 remains the strongest, most consistently supported signal for search visibility.
  • Write H2s in the language people actually search — "How to Add a Table of Contents" ranks better than a vague "More Info."
  • Don't repeat near-identical headings across a page purely for keywords; it reads as duplication to both readers and crawlers.
  • Keep the hierarchy unbroken — search engines pull heading structure into featured snippets, so a broken H1→H4 jump can mean your best content gets skipped for one.

Heading Behavior Across Platforms

Syntax is universal; auto-TOC generation is not:

Platform Auto TOC
GitHub Yes, for supported file types
GitLab Yes
Jekyll Via plugin
Hugo Via shortcode/theme — varies significantly by theme
Docusaurus Yes, built-in
MkDocs Yes, built-in
GitBook Yes, built-in
Obsidian Via plugin/outline view
Notion Via linked TOC block

If you're publishing docs on a static site generator, verify your specific theme's anchor and TOC behavior before hardcoding #anchor links — Hugo in particular varies by theme.

Inline Formatting in Headings

Most parsers allow links, inline code, and emoji inside headings:

## [API Documentation](https://example.com)
## Installing `npm`
## 🚀 Getting Started

Widely supported on GitHub, GitLab, and Obsidian — but avoid stacking multiple formatted elements in one heading, since it hurts scannability and can break some auto-generated TOC renderers.

Headings and Table of Contents

Separate from this site's own page navigation — this is about the TOC generated inside your own Markdown document when it's rendered. A consistent hierarchy is what makes that possible:

# User Guide
## Installation
## Configuration
### Environment Variables
## Troubleshooting

That produces a nav tree that mirrors the outline exactly. Generate one automatically with the Markdown TOC Generator.

Accessibility and Document Structure

Screen readers jump directly from one heading to the next by level — so a broken hierarchy (H2 straight to H4) isn't just a visual inconsistency, it's a navigation dead-end for assistive tech users. Keep every level sequential and reserve H1 for the single page title.

Common Heading Mistakes

Mistake Fix
##Heading (no space) ## Heading
Skipping H1 → H4 Follow the sequence: H1 → H2 → H3
Multiple H1s on one page One H1, reserved for the page title (see Headings and SEO)
No blank line before/after heading Add blank lines for parser compatibility
Long, paragraph-style heading text Keep headings short and scannable

For general Markdown formatting slips beyond headings, see Common Markdown Mistakes.

Best Practices Checklist

  • Follow H1 → H2 → H3 in sequence — never skip a level
  • One space after every #, blank line before and after each heading
  • Set a custom anchor ID ({#id}) if the heading text may change later
  • Keep heading text under ~60 characters where possible

Frequently Asked Questions

  1. 1

    Can I use multiple H1 headings in one document?

    Most parsers allow it technically, but for SEO and consistent document structure, use exactly one H1 as the page title and organize everything else with H2/H3.

  2. 2

    What's the real difference between ATX and Setext headings?

    ATX (#) supports all six levels and is the modern standard. Setext (=== / ---) only supports H1 and H2 and is considered legacy syntax — use it only when editing older documents that already use it.

  3. 3

    How do I stop my anchor link from breaking when I rename a heading?

    Set a custom heading ID where your platform supports it ({#custom-id} in kramdown, Pandoc, Docusaurus; {: #id } in MkDocs). GitHub and GitLab don't support custom IDs — the anchor is always auto-generated from the current heading text.

  4. 4

    Do Hugo and Jekyll generate heading anchors the same way as GitHub?

    No. Both use their own slug logic (often theme- or plugin-dependent for Hugo, kramdown-based for Jekyll), so a heading that produces #my-heading on GitHub may generate a different anchor on your static site — always verify in your local build.

  5. 5

    Does heading structure actually affect SEO?

    Yes, indirectly — search engines use heading hierarchy to understand page structure and can pull H2/H3 text into featured snippets. A single clear H1 and logically nested H2s help; keyword-stuffed or duplicated headings don't.

  6. 6

    Why isn't my heading rendering at all?

    Almost always a missing space after #, more than six # characters, or a missing blank line before the heading in a stricter parser. Check all three first.