Skip to content

MD018 - No missing space after hash in heading

Aliases: no-missing-space-atx

What this rule does

Ensures there's a space between the # symbols and the heading text.

Why this matters

  • Readability: Headings without spaces look cramped and are harder to read
  • Compatibility: Some Markdown processors won't recognize headings without spaces
  • Standards: Proper spacing follows Markdown best practices

Examples

✅ Correct

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

❌ Incorrect

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

🔧 Fixed

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

Configuration

Option Type Default Description
magiclink boolean false Enable MagicLink support for issue/PR references
tags boolean null Recognize #word as tags instead of malformed headings. Defaults to true for Obsidian flavor, false otherwise

When magiclink = true, this rule skips PyMdown MagicLink issue/PR references at the start of a line. This prevents false positives when using MagicLink's auto-linking syntax for patterns like #123.

[MD018]
magiclink = true

Example

# PRs that are helpful for context

#10 discusses the philosophy behind the project, and #37 shows a good example.

#Summary

With magiclink = true:

  • #10 and #37 are not flagged (MagicLink issue references)
  • #Summary is flagged (non-numeric, likely a malformed heading)

Special cases

This rule correctly handles:

  • Emoji hashtags like #️⃣ and #⃣ (not treated as headings)
  • Content inside HTML blocks and comments (e.g., CSS selectors like #id)
  • YAML frontmatter comments
  • Indented patterns (not at column 1)

Tag syntax support

When tags = true, this rule skips #word patterns that look like tags (e.g., #todo, #project/active) instead of treating them as malformed headings.

Tags are recognized when they start with # followed by a non-digit, non-space character. Multi-hash patterns like ##tag are always treated as malformed headings, and #123 (starting with a digit) is not a valid tag.

When tags is not explicitly set, it defaults to true for Obsidian flavor and false otherwise. This means Obsidian users get tag support automatically, while users of other flavors can opt in:

[MD018]
tags = true

Example

# Real Heading

#todo this is a tag

#project/active nested tag

##Introduction

With tags = true:

  • #todo and #project/active are not flagged (recognized as tags)
  • ##Introduction is flagged (multi-hash, clearly a malformed heading)
  • #123 is flagged (tags cannot start with digits)

Automatic fixes

This rule automatically adds a space after the # symbols to properly format the heading.

Learn more

  • MD019 - No multiple spaces after hash in heading
  • MD020 - No missing space in closed heading
  • MD021 - No multiple spaces in closed heading
  • MD022 - Headings should be surrounded by blank lines