How to build yaml frontmatter for blog posts
- Step 1Bring in the post body — Use Paste text to drop the Markdown article into the textarea, or switch to Upload file and pick a single
.mdor.txtfile. The body is whatever you supply here — there is no separate body field. - Step 2Fill the Title and Slug — Type the human title (e.g.
Shipping Faster With Astro) and a URL slug (e.g.shipping-faster-with-astro). Both are optional — leave a field blank and it is omitted from the output entirely. - Step 3Set the Date — The Date field is free text — type an ISO date such as
2026-06-13. There is no auto-fill and no validation, so whatever you enter is written verbatim.js-yamlsingle-quotes date-looking values so they round-trip as strings. - Step 4Add Description and Tags — Description feeds your SEO meta description. Tags accept a comma-separated list like
astro, performance, ssgand become a YAML array. Blank descriptions or tags are simply left out of the block. - Step 5Decide the Draft flag — Tick Draft to publish-block the post in your SSG. Unlike the other fields,
draftis always written to the output — unchecked producesdraft: false, checked producesdraft: true. - Step 6Run and save into your content folder — Click run, review the prepended block in the preview, then download. Save the result into your blog's posts directory (
content/posts/,_posts/,src/content/blog/, etc.) keeping the original filename.
The six fields and exactly what they emit
These are the only controls in the form. The client renders five text inputs plus one checkbox — there is no custom-field section and no per-SSG preset. Empty text fields are dropped; draft is always present.
| Field | Input type | Emitted as | When blank / unchecked |
|---|---|---|---|
title | Text | title: My Post (quoted if it contains YAML-special chars) | Omitted from the block |
date | Text (free-form) | date: '2026-06-13' (date-like strings single-quoted) | Omitted from the block |
slug | Text | slug: my-post | Omitted from the block |
description | Text | description: 'Subtitle: with colon' (auto-quoted as needed) | Omitted from the block |
tags | Text, comma-separated | YAML block sequence: tags: then - tag | Omitted from the block |
draft | Checkbox | draft: false or draft: true | Always written as draft: false |
SSG compatibility of the emitted YAML
The tool always emits YAML delimited by ---. Compatibility below reflects how each generator reads that block, not extra features this tool adds. Fields outside the six (layout, categories, weight, ogImage, etc.) must be added by hand after running.
| Generator | Reads `---` YAML? | Notes for blog posts |
|---|---|---|
| Hugo | Yes | Also supports TOML (+++) and JSON, but YAML works everywhere. draft: true hides the post unless you build with --buildDrafts |
| Jekyll / GitHub Pages | Yes | Requires the date in the filename (YYYY-MM-DD-slug.md); add layout: post manually — it is not one of the six fields |
| Astro Content Collections | Yes | Validate against your zod schema; this tool does not enforce a schema, so extra/required fields are on you |
| Next.js MDX | Yes | Parsed by gray-matter or next-mdx-remote; tags array maps cleanly to a frontmatter prop |
| Eleventy (11ty) | Yes | draft is not built-in to 11ty — wire it to a permalink: false or filter yourself |
| Gatsby | Yes | Read by gatsby-transformer-remark; arrays and dates pass through to GraphQL nodes |
Cookbook
Real before/after examples for blog publishing. The left side is what you paste/upload; the right side is the downloaded .md. Field order in the output is always title → date → slug → description → tags → draft.
Bare post body gets a full block
A post copied out of a Google Doc has no metadata. You fill all six fields. The block is prepended above the existing first heading, which is left exactly as written.
Paste (body):
# Shipping Faster With Astro
We cut our build time in half this quarter...
Form: title=Shipping Faster With Astro, date=2026-06-13,
slug=shipping-faster-with-astro,
description=How we halved Astro build times,
tags=astro, performance, ssg, draft=unchecked
Download:
---
title: Shipping Faster With Astro
date: '2026-06-13'
slug: shipping-faster-with-astro
description: How we halved Astro build times
tags:
- astro
- performance
- ssg
draft: false
---
# Shipping Faster With Astro
We cut our build time in half this quarter...Only Title filled — everything else dropped except draft
You just want a title on a quick post. Blank fields are omitted; draft is the one field that is always present.
Form: title=Quick Note, all other fields blank, draft unchecked Download: --- title: Quick Note draft: false --- (body unchanged)
Description with a colon stays valid
A subtitle-style description contains a colon, which would break a hand-typed YAML block. The serializer quotes it automatically.
Form: description=Case study: a 40% speedup Download: --- description: 'Case study: a 40% speedup' draft: false ---
Marking a post as a draft
Ticking the Draft box flips the always-present flag to true so Hugo (with default settings) leaves it out of the build.
Form: title=Untitled Idea, draft=checked Download: --- title: Untitled Idea draft: true --- hugo build -> post excluded hugo build -D -> post included (build drafts)
Re-running on a post that already has frontmatter
You imported a post that already carries an old block. The tool strips the existing leading YAML/TOML and writes a fresh one — no duplicate blocks.
Paste (body with old block): --- title: Old Title date: 2024-01-01 --- # Old Title Content here. Form: title=New Title, date=2026-06-13 Download: --- title: New Title date: '2026-06-13' draft: false --- # Old Title Content here.
Edge cases and what actually happens
`draft: false` appears even though you never touched the box
By designThe draft checkbox defaults to false and the engine writes the field whenever it is defined (if (fields.draft !== undefined)). So every output includes draft: false unless you tick the box. If your SSG dislikes a draft key on published posts, delete that one line after downloading.
Leaving Title and everything else blank
ExpectedEmpty text fields are skipped (if (fields.title) etc.), so a fully blank form still produces a valid block — just ---, draft: false, ---. It is harmless but rarely what you want; fill at least Title and Date for a real post.
Existing TOML (`+++`) frontmatter on a Hugo post
ReplacedThe splitter recognises a leading TOML block delimited by +++ and strips it before prepending the new YAML. Your TOML metadata is not converted — it is discarded — so copy any keys you still need (weight, menu, aliases) before running and re-add them by hand.
You need `categories`, `layout`, `weight`, or `ogImage`
Not a fieldThe form has exactly six fields. There is no categories, layout, weight, menu, or ogImage control and no custom-field section. Add those keys manually to the downloaded block, or fold extras into the comma-separated tags field if your taxonomy allows it.
Typing a non-ISO date like `June 13, 2026`
Written verbatimThe Date field is plain text with no validation or auto-fill. Whatever you type is serialized as-is (quoted if it looks date-like). Jekyll and Hugo expect ISO YYYY-MM-DD; a free-form string can cause a build error in strict SSGs. Use 2026-06-13 format.
Tags with trailing commas or extra spaces
Cleanedtags is split on commas, each entry is trimmed, and empty entries are dropped. So astro, , ssg, yields exactly two tags (astro, ssg). You do not need to tidy the input by hand.
Output is YAML even though Hugo could use TOML
By designThis tool only emits YAML (---). It never produces TOML or JSON frontmatter. Hugo reads YAML fine, so this is rarely a problem — but if your repo standardises on TOML you will need to convert the block manually after downloading.
Post body exceeds the free 1 MB / 500,000-character limit
Tier limitFree tier caps a single file at 1 MB or 500,000 characters, whichever is hit first. A normal blog post is a few KB, so this only bites on very long imports or accidental whole-site pastes. Pro raises the cap to 10 MB / 5,000,000 characters.
Trying to process several posts at once
Single fileThe tool accepts one file at a time (acceptsMultiple: false). For a bulk migration, run posts one by one, or script the equivalent: strip the leading block and prepend your generated YAML in your own pipeline.
Frequently asked questions
Will this overwrite frontmatter my post already has?
Yes. If the body you paste or upload starts with a --- (YAML) or +++ (TOML) block, that block is detected and stripped, then a fresh YAML block built from your form fields is prepended. The prose after the old block is preserved exactly. Copy any keys you want to keep before running, because the old block's contents are discarded, not merged.
Why does every post come out with `draft: false`?
The draft checkbox defaults to false and the field is always written to the output, unlike the five text fields which are omitted when blank. If you do not want a draft key on a published post, delete that single line after downloading, or just leave it — most SSGs treat draft: false as a normal published post.
Can I add custom fields like `layout` or `categories`?
Not in the form — it has exactly six controls (title, date, slug, description, tags, draft) and no custom-field section. Add any SSG-specific keys (layout, categories, weight, menu, ogImage) by hand to the downloaded block. For Jekyll, layout: post is the most common one you will add manually.
Does it output TOML for Hugo?
No. The output is always YAML delimited by ---. Hugo reads YAML perfectly, so for most blogs this is fine. If your Hugo repo standardises on TOML (+++), convert the downloaded block yourself — this tool does not emit or convert to TOML.
How should I format the date?
Type an ISO date, YYYY-MM-DD, e.g. 2026-06-13. The field is free text with no auto-fill and no validation, so whatever you type is written verbatim. Date-looking values are single-quoted by the serializer so they round-trip as strings. Non-ISO formats can cause build errors in Jekyll and strict SSGs.
How do I enter multiple tags?
Type them comma-separated in the Tags field, e.g. astro, performance, ssg. They are split on commas, trimmed, and emptied entries dropped, then emitted as a YAML block sequence (one - tag per line). You do not indent or quote them yourself.
Does the date auto-fill to today?
No. There is no default date — the field starts empty and is only written if you type something. If you want today's date in the block, type it in. (Earlier descriptions of this tool that claimed an auto-fill were inaccurate.)
Which static site generators is the output compatible with?
The --- YAML block is read by Hugo, Jekyll, GitHub Pages, Astro Content Collections, Next.js MDX, Eleventy, Gatsby, and VitePress. Compatibility is about the delimiter and YAML syntax — generator-specific required fields (like Jekyll's filename date or an Astro zod schema) are still your responsibility.
Can it process my whole blog folder at once?
No — it takes one file (or one paste) at a time. For a multi-post migration, run posts individually. The split-and-prepend logic is simple enough to replicate in a build script if you need to bulk-process hundreds of files.
Is my draft uploaded anywhere?
No. Processing runs in your browser, whether you paste text or upload a single .md/.txt file. Only an anonymous processed-file counter is recorded server-side for dashboard stats — never your content.
What if I only want to add a slug and nothing else?
Fill just the Slug field and leave the rest blank. The output will contain slug: ... plus the always-present draft: false, and nothing else. Every blank text field is omitted, so the block stays minimal.
What tools pair well with this for a blog workflow?
Generate a table of contents with md-toc-generator, catch broken Markdown before publishing with md-lint, tidy spacing with md-prettifier, fix relative image paths during a move with md-image-path-rewriter, and preview the rendered post with md-to-html.
Privacy first
All Markdown processing runs locally in your browser using JavaScript. No file is ever uploaded to JAD Apps servers — only metadata counters are saved for signed-in dashboard stats.