Author your first post with BlogSiteFrontMatter
By the end of this tutorial, a running BlogSite at http://localhost:5000 surfaces a single, fully-populated post on the home page, the archive, the per-tag index, and /rss.xml — the placeholder from the scaffold tutorial swapped for a post of your own. Along the way, every BlogSiteFrontMatter field a post author touches comes into view, along with the surface each one lights up and how to confirm RSS is on by opening /rss.xml.
Prerequisites
- .NET 11 SDK installed
- Completed Scaffold a blog with BlogSite (or have that example's
Program.csand a single placeholder post ready to reuse) - A code editor that renders YAML front matter cleanly (VS Code, Rider, etc.)
The finished code for this tutorial lives in examples/BlogSiteFirstPostExample.
1. Start from a bare-minimum front-matter block
This section replaces the scaffold's placeholder post with a new file Content/Blog/my-first-post.md that carries only the three fields every post truly needs — title, description, and date — then confirms it renders on the home listing, the archive, and the RSS feed even in this minimal state.
- 1
Delete
Content/Blog/hello-world.mdand createmy-first-post.mdThe scaffold tutorial left a placeholder post named
hello-world.mdinContent/Blog/. Delete it, then create a new filemy-first-post.mdin the same folder. The filename (minus.md) becomes the URL slug, so the post serves at/blog/my-first-post/. - 2
Paste in title, description, and date only
Paste the Stage 1 markdown body into the new file. These three fields are the smallest front matter that lets a BlogSite post render cleanly:
titleis the only field required byIFrontMatter;descriptionis what the home card, archive card, and RSS<description>element all pull from; anddatedrives both the archive sort order and the RSS<pubDate>element.--- title: Shipping a tiny content engine for weekend projects description: Notes from the first month of building Pennington. date: 2026-04-10 --- Welcome to the first real post on this blog. The scaffold from the previous tutorial gave us a running BlogSite with one placeholder post; this post replaces it. ## What's here so far Just title, description, and date. That is enough for the home listing, the archive page, and the RSS feed to light up.The two
---fences delimit the YAML front matter block. Thedate:value parses as an ISO-8601 date; any format that round-trips as a date string works. For the full list of recognised front-matter keys, see the Pennington.BlogSite.BlogSiteFrontMatter reference page.
Checkpoint — The new post replaces the scaffold placeholder
- Run
dotnet runfrom the example project - Visit
http://localhost:5000/— a single recent-posts card titled Shipping a tiny content engine for weekend projects appears with the stage-1 description - Visit
http://localhost:5000/archive— the same post appears as the only archive entry, dated 2026-04-10 - Visit
http://localhost:5000/blog/my-first-post/— the post body renders with its H1 and paragraph text
2. Populate every BlogSiteFrontMatter field
Next, the front-matter block expands to cover every BlogSiteFrontMatter field a post author touches — author, tags, series, repository, sectionLabel, and redirectUrl — and each one lights up a different surface in the running site.
- 1
Replace the front matter with the fully-populated block
Replace the Stage 1 YAML block with the Stage 2 block below. Here's what each new key does:
author:— becomes the byline on the post page and the<author>element in the RSS feedtags:— builds/tags/<tag>/index pages and renders as chips on the post pageseries:— threads posts together under a shared banner on the post chromerepository:— renders as a "Source Code" link card on the post pagesectionLabel:— groups the post under a named slice of the archiveredirectUrl:— stays empty here because this post has no previous home on the web; set it when migrating a post from another URL
--- title: Shipping a tiny content engine for weekend projects description: Notes from the first month of building Pennington — why Markdig plus Razor components plus a little YAML beats reaching for a heavier framework. date: 2026-04-10 author: Author Name tags: - pennington - dotnet - blogging series: Pennington Field Notes repository: https://github.com/example/pennington-field-notes sectionLabel: field-notes redirectUrl: --- Welcome to the first real post on this blog. The scaffold from the previous tutorial gave us a running BlogSite with one placeholder post; this post replaces it with something the BlogSite template actually has opinions about. ## What the front matter is doing Each field in the block above lights up a different surface — the archive card, the post header, the /tags/<tag> listings, the RSS channel, the JSON-LD metadata — and walking through them in order is the point of this tutorial.The list-of-strings shape for
tags:is YAML's block sequence (- valueper line). For the full record definition, see Pennington.BlogSite.BlogSiteFrontMatter. - 2
Reload and confirm every surface lit up
With the file saved, reload the running site and verify each new field in turn. No code changes are needed — the host from the scaffold tutorial stays untouched.
Checkpoint — Each field has a visible home
- Visit
http://localhost:5000/blog/my-first-post/— the post header shows the byline Author Name, the series banner Pennington Field Notes, three tag chips (pennington, dotnet, blogging), and a Source Code link card pointing at therepository:URL - Visit
http://localhost:5000/tags/pennington/— the post appears on the per-tag index; repeat for/tags/dotnet/and/tags/blogging/ - Visit
http://localhost:5000/archive— the archive card carries the longer description from the Stage 2 block
3. Turn on the built-in RSS feed
Now to make the RSS wiring explicit. EnableRss already defaults to true, but putting the line in source gives a concrete symbol to flip when turning the feed off, and confirms that the populated front matter reached the feed items.
- 1
Set
EnableRss = trueexplicitly inProgram.csOpen
Program.csfrom the scaffold tutorial and add one explicit line inside theAddBlogSite(...)block:EnableRss = true,. This mirrors the default (see theEnableRssrow inBlogSiteOptions) but makes the intent clear. Also confirmCanonicalBaseUrlis set — it already is from the scaffold — because the RSS feed uses it to build absolute<link>elements.using Pennington.BlogSite; var builder = WebApplication.CreateBuilder(args); // Tutorial 1.3.20 extends the BlogSiteScaffoldExample host with a fully // populated post. The host shape is identical to tutorial 1.3.10 — the // teaching surface this tutorial adds is entirely in Content/Blog/my-first-post.md, // where every field on `BlogSiteFrontMatter` that the reader will ever touch is // populated with a meaningful value. `EnableRss = true` is the default (see // `BlogSiteOptions`) — we set it explicitly so the tutorial's RSS step has a // symbol to point at. `EnableSitemap` likewise defaults to true. builder.Services.AddBlogSite(() => new BlogSiteOptions { SiteTitle = "First Post Blog", Description = "A BlogSite tutorial app demonstrating a fully-populated BlogSiteFrontMatter.", CanonicalBaseUrl = "https://example.com", AuthorName = "Author Name", AuthorBio = "Writing about software, tools, and the occasional side project.", // Explicit for teaching value even though both default to true. EnableRss = true, EnableSitemap = true, }); var app = builder.Build(); app.UseBlogSite(); await app.RunBlogSiteAsync(args);UseBlogSite()maps the/rss.xmlroute whenEnableRssistrue(see Built-in BlogSite routes). The template builds the feed — populated front matter is what makes each feed item meaningful. - 2
Open
/rss.xmland confirm the post is an entryVisit
http://localhost:5000/rss.xmlin the browser (orcurlit). Confirm the post appears as an<item>with every front-matter field mapped to its RSS element:title:→<title>,description:→<description>,date:→<pubDate>,author:→<author>, and the canonical post URL →<link>and<guid>.
Checkpoint — A valid RSS feed with the populated post
- Visit
http://localhost:5000/rss.xml— the browser either renders the feed (Firefox) or shows raw XML (Chrome/Edge) - The
<channel>carries the site title First Post Blog and the configured description - A single
<item>element contains<title>Shipping a tiny content engine for weekend projects</title>,<description>with the stage-2 text,<pubDate>for 10 Apr 2026,<author>Author Name</author>, and a<link>whose value starts with the configuredCanonicalBaseUrl
Summary
- A Pennington blog post backed by
BlogSiteFrontMattermaps predictably onto each blog surface — title/description/date for listings, author for byline and RSS, tags for/tags/<tag>/indexes, series for the shared banner, repository for the source-code link card. AddBlogSitebindsAddMarkdownContent<BlogSiteFrontMatter>— not the coreBlogFrontMatter— so the YAML keys a post accepts are the ones onBlogSiteFrontMatter.- The
EnableRssoption onBlogSiteOptionsturns the built-in RSS feed on or off, and populated front matter flows into every RSS item element. - Dropping a new
Content/Blog/*.mdfile brings it straight to the home page, the archive, every tag it claims, and/rss.xml— noProgram.cschanges needed.