Complete Guide to Markdown Tags: Inline Tags and Front Matter Tags
When people talk about Markdown tags, the first reaction is usually "isn't that a blog-only feature?" Fair point — John Gruber's original Markdown spec didn't include tags at all [^1]. But as Markdown has become the go-to format for managing notes, writing blogs, and maintaining documentation, tags have become essential. You need some way to organize hundreds of articles by topic.
This article covers everything about Markdown tags: how to write inline tags (#tag), how to use the tags field in Front Matter, what the differences are across platforms, and how to pick good tag names.
Markdown Tags Quick Reference
Here's an overview table for quick lookup. Each type is explained in detail below.
| Tag Type | Syntax | Use Case | Typical Platform |
|---|---|---|---|
| Inline tag | #tagname | Tag anywhere in text | Obsidian, Logseq |
| Nested tag | #parent/child | Organize tags hierarchically | Obsidian |
| Front Matter list | tags: [a, b] | Article-level metadata | Jekyll, Hugo, VitePress |
| Front Matter multiline | tags: + - a | Same, for many tags | Same |
| Front Matter string | tags: a b c | Space-separated (Jekyll only) | Jekyll |
Key insight: Markdown tags are not part of the original spec. They're implemented by individual tools (static site generators, note-taking apps), so syntax and behavior vary across platforms. Let's break them down into two categories.
Inline Tags: Tag as You Write
Inline tags are #tagname written directly in the Markdown body. They look like social media hashtags, but functionally they're for categorizing notes.
Obsidian Inline Tags
Obsidian has the most mature inline tag support. Write #tagname anywhere in your text and Obsidian automatically recognizes it, showing it in the left tag panel [^2].
Learned the basics of Markdown syntax today #markdown
This note is related to JavaScript #javascriptA few detail rules:
- Must be preceded by a space or start of line —
this is#tagwon't be recognized,this is #tagwill - Cannot be followed immediately by regular text —
#tagtextonly recognizes#tag(space marks the end) - No spaces allowed —
#my tagonly recognizes#my; use#my_tagor#my-taginstead - Case-insensitive —
#Markdownand#markdownare the same tag - Numbers are allowed —
#2026planis valid, but pure numbers like#123may not work in some versions
Nested Tags: Organize with Slashes
Obsidian supports nested tags using /, essentially creating a folder structure for your tags [^2]:
#inbox/to-read
#inbox/to-process
#project/frontend
#project/backendIn the tag panel, #inbox will show to-read and to-process as collapsible sub-tags. Searching for #inbox also matches all child tags. This is incredibly useful once you have many tags — a flat list of hundreds of tags is impossible to navigate.
There's no hard limit on nesting depth, but in practice two to three levels is enough. Going deeper just adds management overhead.
Limitations of Inline Tags
The biggest issue with inline tags is tool dependency. The #tag syntax means nothing to static site generators like Jekyll or Hugo — they only read metadata from Front Matter. On GitHub, #tag would be rendered as an H1 heading.
So if you use Obsidian for note-taking, inline tags are convenient. But if your files will be published to a blog or GitHub, you'll still need Front Matter tags.
Front Matter Tags: Categorize in Metadata
Front Matter tags are the tags field written in the YAML header, used to tag the entire article. This is the approach supported by most static site generators and tools.
YAML List Syntax
Two equivalent formats — pick whichever you prefer:
Inline style (for a small number of tags):
---
title: Markdown Tags Guide
tags: [markdown, tags, tutorial]
---Multiline style (for many tags):
---
title: Markdown Tags Guide
tags:
- markdown
- tags
- tutorial
---I personally prefer the multiline style because adding or removing tags produces cleaner Git diffs — you won't have an entire array changed in one line.
Jekyll's Space-Separated Syntax
Jekyll has a unique way of writing tags — as a space-separated string [^3]:
---
title: My Article
tags: markdown tags tutorial
---Only Jekyll understands this format. Hugo, Hexo, and VitePress all require array syntax. From my testing, Jekyll also correctly parses the array format tags: [a, b], so using arrays in Jekyll projects works fine and has better cross-platform compatibility.
Hugo's Multi-Format Support
Hugo is one of the few static site generators that supports three front matter formats [^4]:
---
title: My Article
tags: [markdown, tags]
---
# TOML
+++
title = "My Article"
tags = ["markdown", "tags"]
+++
# JSON (rarely used)
{
"title": "My Article",
"tags": ["markdown", "tags"]
}In all three formats, Hugo treats tags as a taxonomy, automatically generating tag pages like /tags/markdown/.
Combining Both Tag Types in Obsidian
Obsidian is unique — it supports both inline tags and Front Matter tags, and merges them into the same system [^2]. Whether you write #javascript in the body or tags: [javascript] in the front matter, Obsidian groups them under the same javascript entry in the tag panel.
So how should you choose between the two? My approach:
- Front Matter tags for article-level classification — what this article "is about", like
tags: [tutorial, markdown, frontend] - Inline tags for paragraph-level markers — what this section "involves", like
#review-later#important#bug
The benefit of this split: Front Matter tags are great for batch searching "all tutorial articles", while inline tags help you quickly locate "which paragraphs are marked as important" while reading.
Markdown Tag Naming Rules
Regardless of which tag format you use, there are some universal rules for naming. These are lessons I learned the hard way.
Allowed Characters
| Character | Inline Tags | Front Matter Tags | Notes |
|---|---|---|---|
| Chinese characters | ✅ | ✅ | Obsidian supports Chinese tags perfectly |
| English letters | ✅ | ✅ | |
| Numbers | ✅ | ✅ | |
Underscore _ | ✅ | ✅ | Used as space replacement |
Hyphen - | ✅ | ✅ | |
Slash / | ✅ (Obsidian) | ❌ | Used for nested hierarchy in inline tags |
| Space | ❌ | ✅ (with quotes) | Inline tags break at spaces |
# | ❌ | ✅ (with quotes) | Conflicts with inline tag prefix |
Naming Tips
Keep it short — a tag is not a description. Two to four words is plenty. #frontend beats #frontend-development-tech-stack any day.
Be consistent — use either all Chinese (#前端) or all English (#frontend). Mixing makes the tag panel messy. I used to mix #javascript and #前端, and when I wanted to find all frontend-related notes, they were scattered across two different tags.
Avoid synonyms — #js and #javascript are two different tags. Pick one and stick with it. You can delete the less-used one from the tag panel — Obsidian will remind you which notes used it.
Platform Comparison for Markdown Tags
A single table showing tag support across platforms:
| Feature | Obsidian | Jekyll | Hugo | Hexo | MkDocs Material |
|---|---|---|---|---|---|
| Inline tags | ✅ | ❌ | ❌ | ❌ | ❌ |
| Nested tags | ✅ | ❌ | ✅ | ❌ | ✅ (paid) |
| Front Matter tags | ✅ | ✅ | ✅ | ✅ | ✅ |
| Auto tag pages | ❌ | ✅ | ✅ | ✅ | ✅ |
| YAML array format | ✅ | ✅ | ✅ | ✅ | ✅ |
| TOML format | ❌ | ❌ | ✅ | ❌ | ❌ |
| Tag panel/index | ✅ | Plugin needed | ✅ | Plugin needed | ✅ |
One point that confuses people: the difference between tags and categories. In Hexo and Jekyll, categories are hierarchical (an article belongs to one category chain), while tags are flat (an article can have multiple tags) [^3]. Obsidian doesn't make this distinction — it only has tags.
Frequently Asked Questions
What's the difference between tags and keywords in Front Matter?
tags are classification labels used to organize content, typically displayed as clickable tag links on a website. keywords are SEO keywords written in the HTML meta tag and not shown on the page. Some themes use tags as SEO keywords too, but semantically they're different things.
What if I have too many tags?
Tag sprawl is a real problem. Once I was organizing my notes and found over 200 tags in the panel, half of which had only been used once. Here's what I did:
- Merge synonyms — combined
#js,#JS, and#javascriptinto#javascript - Remove low-frequency tags — tags used only 1-2 times were either merged into broader tags or deleted
- Replace flat tags with nested tags — changed
#css#css-animation#css-layoutto#css/animation#css/layout
The goal is to keep tags under 50, with each tag linked to at least 3 articles.
What about the conflict between inline tags and Markdown headings?
In standard Markdown, lines starting with # are H1 headings. So #tag would be rendered as a heading on GitHub or GitLab, not a tag. Only note-taking tools like Obsidian and Logseq treat #word in the body as a tag.
If your Markdown files need to work across multiple platforms, keep inline tags for Obsidian only and use Front Matter tags for anything you're publishing.
Honestly, the syntax itself is just a few lines, but the gotchas are all in the details. Figure out which platform your files will end up on, pick the right tag format, and stick to consistent naming habits. Your tag system will actually help you instead of adding chaos.
References
[^1]: John Gruber, Markdown: Syntax, Daring Fireball — The original Markdown spec does not define tags [^2]: Obsidian Help, Tags, help.obsidian.md — Official Obsidian tag documentation [^3]: Jekyll Documentation, Front Matter Defaults, jekyllrb.com — How Jekyll handles tags and categories [^4]: Hugo Documentation, Front Matter, gohugo.io — Hugo's three front matter formats and taxonomies support