This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy under /_llms/. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content Skip to navigation
Reference

Front matter key reference

Every built-in YAML front-matter key recognized by the shipped IFrontMatter implementations, with type, default, source interface, and applicable front-matter record.

YAML keys parsed into the five shipped IFrontMatter records — DocFrontMatter, BlogFrontMatter, BlogPostFrontMatter, DocSiteFrontMatter, BlogSiteFrontMatter. See Pennington.FrontMatter.IFrontMatter for the interface surface and The front-matter capability system for the design rationale.

Keys

Rows are alphabetical by YAML key. Each entry shows the records that expose the key, the declaring interface (IFrontMatter, one of the capability interfaces, or record-local), and every distinct type and default across records.

atprotoRkey string?
Default: null

Applies to: BlogPostFrontMatter, BlogSiteFrontMatter. Declared on: record-local.

Record key of this post's published site.standard.document record (Standard Site), if any.
author string / string?
Default: "" / null

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter. Declared on: record-local.

Author name shown in the post byline and RSS feed.
date DateTime?
Default: null

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter. Declared on: IFrontMatter.

Publication date. Posts are ordered by this date, newest first.
description string?
Default: null

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

Short description used for the meta description and post listings.
isDraft bool
Default: false

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

When true, the post is skipped during production builds.
llms bool
Default: true

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

When false, the post is excluded from the generated llms.txt output.
order int
Default: 2147483647

Applies to: DocFrontMatter, DocSiteFrontMatter. Declared on: IOrderable.

Sort order within the containing section. Lower values appear first.
redirectUrl string?
Default: null

Applies to: BlogPostFrontMatter, BlogSiteFrontMatter, DocSiteFrontMatter. Declared on: IRedirectable.

When set, the post emits a client-side redirect to this URL instead of normal content.
repository string
Default: ""

Applies to: BlogSiteFrontMatter. Declared on: record-local.

URL to the post's source repository or related project (optional).
search bool
Default: true

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

When false, the post is excluded from the search index.
searchOnly bool
Default: true / false

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

Always true: posts are indexed for search and llms.txt but kept out of the documentation navigation sidebar. Not author-settable — the blog has its own index and tag pages.
sectionLabel string?
Default: null

Applies to: BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: ISectionable.

Section heading this page belongs under in navigation.
series string / string?
Default: "" / null

Applies to: BlogFrontMatter, BlogSiteFrontMatter. Declared on: record-local.

Series name grouping related posts together.
tags string[]
Default: []

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: ITaggable.

Tags applied to the post for the tag index and browse-by-tag pages.
title string
Default: "" / "Empty title"

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

Post title rendered in the browser tab and post heading.
uid string?
Default: null

Applies to: BlogFrontMatter, BlogPostFrontMatter, BlogSiteFrontMatter, DocFrontMatter, DocSiteFrontMatter. Declared on: IFrontMatter.

Stable identifier used for cross-references ([text](xref:uid)).

Parse rules

  • YAML keys are the camelCase form of the C# property names. Matching is case-insensitive.
  • Unknown keys are dropped with a warning diagnostic in lenient mode (the default outside build); in strict mode (the build default) they throw a YamlException and fail the parse.
  • Lenient versus strict is controlled by PenningtonOptions.FrontMatter.StrictUnknownKeys, settable in the AddPennington(options => …) callback. It defaults to false (lenient), and -- build flips it to true unless the host has already set it. diag frontmatter prints the active value.
  • Absent keys fall through to the record's init default.

Drafts and scheduled pages

isDraft: true excludes a page from build output entirely: -- build skips the route, so it is never written, never crawled, and its uid does not resolve in the static site. Development requests still render it so authors can preview. A date: set after the build clock has the same effect until the clock catches up (scheduled publishing).

This is the canonical statement of the rule. isDraft is a build switch, not a navigation switch — to keep a page published but out of the sidebar, use searchOnly: true instead, which leaves the route in the build and indexes while hiding it from the rendered navigation tree.

Example

A DocSiteFrontMatter page populating the most common keys:

markdown
---
title: Front matter
description: The YAML block at the top of every markdown page.
tags: [authoring, front-matter]
sectionLabel: authoring
order: 20
uid: kitchen-sink.main.front-matter
---
  
Every page in this site opens with a YAML block between `---` markers.
Those keys drive the sidebar title, description, tags, ordering, draft
state, and cross-reference `uid`. Each built-in front-matter record maps
the same keys onto a strongly-typed record.
  
## The built-in DocSite record
  
The DocSite template uses `DocSiteFrontMatter` under the hood. Its fields
cover the full capability surface — `Title`, `Description`, `IsDraft`,
`Tags`, `Order`, `RedirectUrl`, `Section`, `Uid`, `Search`, and `Llms`.
  
## A custom front-matter record
  
When you need extra fields, declare a record implementing `IFrontMatter`
(plus any capability interfaces you want). This site ships an
`ApiFrontMatter` record used by the API area to add `Namespace` and
`Stability` fields:
  
```yaml
---
title: Symbol reference
namespace: Pennington.Search
stability: preview
order: 30
---
```
  
Declare the record alongside your host project; Pennington discovers it
by type when you call `AddMarkdownContent<ApiFrontMatter>(...)`.

A BlogSiteFrontMatter page populating the blog-only keys (author, series, repository, date):

markdown
---
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 that placeholder with something the BlogSite template actually
has opinions about. Every key in the front-matter 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.
  
## What the front matter is doing
  
`title`, `description`, and `date` are the three fields that drive every
listing surface: the home page card, the `/archive` page, and the RSS item.
`author` flows into the same places plus the per-post byline and the RSS
`<author>` element; when it matches `BlogSiteOptions.AuthorName` the blog
defaults to the configured author bio for the post chrome.
  
`tags` build the `/tags/<tag>/` index pages. The three tags above mean this
post shows up under `/tags/pennington/`, `/tags/dotnet/`, and
`/tags/blogging/`. `series` lets several posts thread together under a
shared banner — a later tutorial walks through grouping posts by series.
`repository` is a hint for "view source" links; `section` groups this post
under a named slice of the archive; `redirectUrl` is left empty because
this post has no previous home elsewhere on the web.
  
## Why you'd bother populating all of it
  
You can absolutely ship a post with only `title`, `description`, and
`date` — the BlogSite will still render it. But each field you populate
turns on one more piece of chrome: RSS readers show the author, social
previews show the description, `/tags/<tag>/` listings pick up the post,
and the series banner threads together the posts that belong together.
Populating the full set once, on the first post, is how you make the rest
of the blog's defaults work for you.
  
The next tutorial wires up the homepage hero, the project grid, and the
social-link icons — so the scaffolded blog starts to feel like a real
personal site rather than an archive of posts.

See also