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 following Obsidian's tag rules: a tag must contain at least one non-numerical character, so #1984 is not a tag but #y1984 and #3d_printing are. Multi-hash patterns like ##tag are always treated as malformed headings.

A leading run of digits is allowed as long as a letter, an underscore, a hyphen, a forward slash or an emoji follows it. Digits followed by other punctuation stay flagged, because #37. and #42, are issue references rather than tags.

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

#3d_printing tag starting with a digit

##Introduction

With tags = true:

  • #todo, #project/active and #3d_printing are not flagged (recognized as tags)
  • ##Introduction is flagged (multi-hash, clearly a malformed heading)
  • #1984 is flagged (all-numeric, so not a valid tag)

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