Markdown Front Matter: The Complete Guide to YAML Metadata Headers
You open a Markdown file and notice a block of text at the top wrapped in --- — that's front matter. It doesn't show up on the page, but behind the scenes it controls the title, date, tags, template, and other important metadata.
If you've built a blog with Jekyll or Hugo, or managed notes in Obsidian, front matter is something you can't really avoid. This article covers the YAML syntax, how to write it, differences across tools, and the pitfalls I've run into myself. A basic understanding of Markdown syntax is all you need to follow along.
What Is Front Matter
Front matter is a block of metadata at the very beginning of a Markdown file. It's delimited by triple dashes --- at the start and end, with YAML key-value pairs in between. It tells the tool processing the file: "Hey, this article has this title, that date, and these categories."
A minimal example:
---
title: My First Article
date: 2026-05-13
---
Content starts here...A few hard rules: front matter must be the very first thing in the file (no blank lines before it), the content between the two --- lines must be valid YAML, and the closing --- is required.
One point of confusion — --- in the body of a Markdown file renders as a horizontal rule, but when it appears at the very top of a file, all major parsers recognize it as the front matter delimiter instead.
YAML Syntax Cheat Sheet
The content inside front matter follows YAML syntax. If you've never worked with YAML before, here's a quick rundown of the essentials.
Basic Key-Value Pairs
title: My First Article
author: Alice
draft: false
views: 1024Add a space after the colon, then write the value. Booleans use true / false, and numbers are written directly.
An easy trap to fall into: if your value contains a colon : or a hash #, you must wrap it in quotes — otherwise the parser will choke. For example:
title: "Getting Started: From Scratch"
description: "Tip #1: Keep it simple"Without quotes, everything after : gets parsed as a new key-value pair, and everything after # is treated as a comment and ignored.
Lists
Both styles work — pick whichever you prefer:
Inline style:
tags: [markdown, yaml, tutorial]Block style:
tags:
- markdown
- yaml
- tutorialNested Objects
seo:
title: "SEO Title"
description: "Page description"
image: "/images/cover.png"Nested levels are indented with two spaces. Honestly, I used to indent with Tab out of habit, and Jekyll builds would just fail — the YAML spec only accepts spaces, and Tab characters break parsing. This is one of the most common mistakes for beginners.
Date Format
ISO 8601 is the recommended format:
date: 2026-05-13
lastmod: 2026-05-13T14:30:00+08:00Some tools only need the date portion, while others expect a full timestamp. Check your tool's documentation for specifics.
Common Fields Reference
Different tools support different fields, but the ones below are widely recognized across most platforms:
| Field | Description | Example |
|---|---|---|
title | Article title | title: My First Article |
date | Publication date | date: 2026-05-13 |
lastmod | Last modified date | lastmod: 2026-05-13 |
author | Author name | author: Alice |
tags | Tag list | tags: [markdown, yaml] |
categories | Categories | categories: [tutorial] |
description | Page description (SEO) | description: A guide to... |
draft | Draft flag | draft: true |
layout | Template to use | layout: post |
slug | Custom URL slug | slug: my-first-post |
weight | Sort order weight | weight: 10 |
These field names are conventions, not part of the YAML standard. In other words, you can write banana: true, but no tool will recognize it — it'll just be silently ignored.
Tool Differences Comparison
This is where front matter gets confusing: the same field can behave differently depending on the tool. I compared several popular ones:
| Feature | Jekyll | Hugo | VitePress | Obsidian |
|---|---|---|---|---|
| Format support | YAML | YAML / TOML / JSON | YAML | YAML |
| Empty front matter | ✅ File is processed | ✅ | ✅ | ✅ |
tags for taxonomy | ✅ | ✅ | ❌ Needs custom handling | ✅ Dataview queries |
draft: true skips build | ❌ Not by default | ✅ Skipped in production | ❌ Needs config | ❌ Display only |
| Nested objects | ✅ | ✅ | ✅ | ⚠️ Some plugins support |
| Custom fields | ✅ Via Liquid templates | ✅ .Params access | ✅ $frontmatter | ✅ Dataview queries |
| TOML support | ❌ | ✅ Uses +++ delimiter | ❌ | ❌ |
Take the draft field as an example: in Hugo, articles with draft: true are automatically skipped during production builds, which is really convenient. But in Jekyll, draft articles get published by default unless you add the --drafts flag or manage them in the _drafts directory.
I figured out these differences the hard way while maintaining both a Jekyll blog and a Hugo documentation site simultaneously.
A Complete Front Matter Example
Here's a configuration you'd actually use in a real project:
---
title: "Markdown Front Matter: A Complete Guide"
date: 2026-05-13T10:00:00+08:00
author: "Alice"
tags:
- markdown
- yaml
- tutorial
categories:
- documentation
description: "From YAML syntax to tool differences — everything you need to know about Markdown Front Matter."
draft: false
slug: markdown-front-matter-guide
seo:
title: "Markdown Front Matter & YAML Metadata"
description: "What front matter is, how to write it, and how tools differ."
image: "/images/frontmatter-cover.png"
---
## Content Starts Here
Your article content...Troubleshooting Common Issues
When front matter goes wrong, it's usually one of these scenarios:
YAML Parse Errors
Symptoms: the tool reports invalid front matter, or field values aren't what you expected.
Things to check:
- Is indentation using spaces? — Tab characters break parsing; this is the #1 cause
- Is there a space after the colon? —
title:my article(wrong) vstitle: my article(correct) - Are special characters quoted? — Values containing
:#[]need quotes - Are list items aligned? — The
-in block-style lists must be consistently indented
Front Matter Not Taking Effect
Symptoms: you wrote front matter but the tool doesn't seem to recognize it.
Common causes:
- A blank line or BOM character before the opening
---(file encoding issue) - Using
...instead of---as the closing delimiter (some tools don't support this) - Wrong file extension (e.g., Jekyll requires
.mdor.html)
Values Parsed Incorrectly
version: 1.0You might expect version to be the string "1.0", but the YAML parser treats it as the float 1.0. The fix: add quotes.
version: "1.0"A similar gotcha applies to true/false/yes/no/on/off — YAML parses all of these as booleans. If your value happens to be one of these words (e.g., tags like tags: [on, off]), remember to quote them.
Parsing Front Matter with Code
Sometimes you need to batch-process Markdown files and extract the metadata from front matter. In the JavaScript ecosystem, the go-to library is gray-matter:
const matter = require('gray-matter');
const file = matter.read('./article.md');
console.log(file.data); // { title: '...', date: '...', tags: [...] }
console.log(file.content); // Content below the '---' delimiterPython users can use python-frontmatter:
import frontmatter
with open('article.md') as f:
post = frontmatter.load(f)
print(post['title']) # Article title
print(post.metadata) # Full front matter dictionary
print(post.content) # Body contentBoth libraries follow the same approach: split a Markdown file into data (metadata) and content (body) so you can handle them separately.