Skip to content

Built-in platform schemas

Eight built-ins describe the front matter contract of a documentation toolchain that is not Docusaurus. Like the Docusaurus schemas, they are platform schemas: they say what your site generator accepts, not what your team has agreed a page should say. That makes them safe to stack under any vocabulary.

Id Toolchain Files it fits Requires
astro:starlight:0.41 Astro Starlight 0.41 .md, .mdx title
antora:page:3.1 Antora 3.1 .adoc, .asciidoc title
sphinx:docinfo:9.1 Sphinx 9.1 .rst nothing
myst:frontmatter:1.10 mystmd 1.10 .md nothing
hugo:page:0.165 Hugo 0.165 .md nothing
jekyll:page:4.4 Jekyll 4.4 .md, .markdown nothing
vitepress:page:1.6 VitePress 1.6 .md nothing
mkdocs:material:9.7 MkDocs 1.6 + Material 9.7 .md nothing

The rule across every platform built-in is to require exactly what the generator refuses to build without. What one demands is therefore a fact about the tool, not a judgement docmeta made on your behalf.

Docusaurus and Sphinx mark no field as mandatory, so their schemas require nothing. They can only ever fail a page on the shape of a value it already carries. Starlight and Antora both error without a page title, so both schemas demand title. A page failing that check was already broken, and docmeta is telling you at review time instead of at build time. MyST requires nothing because it will lift a missing title from the first heading in the document.

Hugo, Jekyll, VitePress and MkDocs require nothing either, for the plainest reason of the lot. All four render a page that has no front matter at all. Hugo falls back to a title derived from the file name. MkDocs works down a list of four title sources and stops at the first that answers. VitePress has a default for every option. In Jekyll it is the presence of the --- block, not its contents, that marks a file for processing. An empty one is valid. That makes all four pure shape checks, which is where their value is. The mistakes they catch are the ones the generator accepts without complaint and then acts on wrongly.

Starlight defines its front matter as a schema you extend rather than replace, so unknown keys are expected and tolerated here too.

Field Type Notes
title string Required. Non-empty.
description string Used for page metadata and SEO.
slug string Overrides the URL slug taken from the file path.
editUrl string | boolean A URL, or false to hide the edit link.
head array Tags injected into <head>; each needs a tag.
tableOfContents object | false minHeadingLevel and maxHeadingLevel, each 1–6.
template doc | splash Anything else is rejected.
hero object title, tagline, image, actions.
banner object Requires content.
lastUpdated date | boolean A YAML date, or a flag.
prev, next boolean | string | object false hides, a string relabels, an object sets link and label.
pagefind boolean Search indexing. Defaults to true.
draft boolean Excluded from production builds.
sidebar object label, order, hidden, badge, attrs.

tableOfContents is written with if/then rather than anyOf so a bad heading level is reported against /tableOfContents/maxHeadingLevel. An anyOf collapses every branch failure onto the parent object, which puts the caret on the wrong line.

Antora page metadata lives in the AsciiDoc document header, not in front matter. The reader takes the = Title line plus every :name: value attribute entry above the first blank line.

Attribute Type Notes
title string Required. The = Title line.
description string AsciiDoc built-in; becomes an HTML meta tag.
keywords string AsciiDoc built-in. A comma-separated string, never a list.
navtitle string Link text used by the navigation.
page-aliases string Comma-separated alternate resource IDs.
page-layout string Which UI template renders the page.
page-partial boolean :page-partial: is true, :!page-partial: is false.
page-role string Body classes. The default UI reserves -toc.
page-toclevels integer 0–5.
page-tags string Comma-separated, same typing as keywords.

Two things about AsciiDoc typing catch people out, and the schema is built around both:

  • Attribute values are text. :keywords: setup, reference reaches the validator as the single string "setup, reference". Typing it as an array would fail every real Antora page, so it is a string.
  • A bare attribute is true. :page-partial: with no value is the boolean true, and the unset form :!page-partial: is false. Numbers are typed too, so :page-toclevels: 3 is the number 3 and not "3".

Antora defines only three predefined page attributes: page-aliases, page-layout and page-partial. The rest of the page-* namespace is yours, and custom attributes pass unchecked.

Sphinx reads file-wide metadata from a field list at the top of the document. Every field is optional, and flag fields are written bare.

Field Type Notes
tocdepth integer Local toctree depth. Does not affect the global sidebar.
orphan boolean Suppresses the not-in-any-toctree warning.
nocomments boolean Suppresses the comment form.
no-search boolean Excludes the page from full-text search.
nosearch boolean Deprecated spelling of no-search.

The set is small on purpose. Sphinx parses every docinfo value as a string, so a field list cannot carry a list or a mapping. Anything richer belongs somewhere else.

The largest built-in, and the one whose value is mostly in its length caps. MyST silently truncates or rejects over-long values, so the caps are the constraint a real document trips.

Field Cap
title, subtitle, description, label 500 characters
short_title, subject 40 characters

Beyond those, the schema types the identity and publication fields. Those are authors, editors, reviewers, affiliations, doi, arxiv, pmid, pmcid, license, open_access, venue, volume, issue and funding. It also types the source links github, edit_url, source_url and binder, and the execution blocks kernelspec and execute. pmcid is checked against PMC followed by digits.

Project-level keys that belong in myst.yml rather than a page are not described, and pass as unknown keys. Those are bibliography, references, requirements and social.

The 28 fields Hugo itself defines. Everything else you see in a Hugo site is a user-configured taxonomy or a custom parameter rather than something Hugo defines. It passes as an unknown key. That covers tags, categories, series, and whatever your theme reads.

Field Type Notes
title, linkTitle, description, summary string None required; Hugo derives a title from the file name.
date, lastmod, publishDate, expiryDate string Typed, not format-checked. See the aside below.
draft, headless, isCJKLanguage boolean A quoted "false" fails here, which is the point.
weight integer Lower sorts first. A quoted number sorts as a string.
aliases, keywords, outputs string array
slug, url, layout, markup, type, translationKey string
menus string | array | map One menu, several, or a map of per-menu options.
cascade map | array of maps The array form carries a _target filter per entry.
build map list, render, publishResources.
sitemap map changefreq is enumerated; priority is 0–1.
resources array Each entry needs src.
params, sites map

The two checks that pay for this schema are weight and draft. Both are routinely written quoted, both are accepted by Hugo without a word, and both then behave wrongly. A string weight sorts lexically, so "10" lands before "9". And draft: "false" is a non-empty string, which is truthy, so the page does not publish.

Deliberately the smallest built-in, because Jekyll’s own contract is small: three global variables and four more for posts.

Field Type Notes
layout string | null null or none suppresses the layout, so null is allowed.
permalink string Overrides the built URL.
published boolean false keeps the document out of the site.
date string Overrides the date parsed from the file name.
category, categories, tags string | string array A YAML list or a space-separated string.

The check worth having is published. published: "false" is a string, every string is truthy, and the post you meant to hold back goes live.

The four options every VitePress theme honours, plus the default theme’s page-level toggles.

Field Type Notes
title, description string Override the site-level values.
titleTemplate string | boolean false drops the suffix.
head array [tag, attrs] pairs injected into <head>.
layout doc | home | page Anything else is rejected.
hero, features object, array Home-layout blocks; typed but not pinned.
outline level | [from, to] | deep | false 1–6.
aside boolean | left
lastUpdated boolean | string A flag, or a date overriding the stamp.
navbar, sidebar, editLink, footer, isHome boolean Page-level toggles.
pageClass string

outline is the field this schema exists for. It takes four different shapes, and VitePress ignores a value it does not recognise rather than complaining. So outline: 9 silently gives you the default rather than a deep outline.

The two keys MkDocs itself defines, plus the seventeen Material for MkDocs adds on top of them. Material is the theme the overwhelming majority of MkDocs sites run. It is where nearly all of the front matter surface lives. Core MkDocs reads title and template and nothing else. So one id covers both, the way vitepress:page:1.6 covers VitePress and its default theme in one.

Field Type Notes
title string MkDocs. Fourth of four title sources, so never required.
template string MkDocs. The theme template rendering this page.
description string The <meta name="description">, and the social card’s text.
author string The <meta name="author">. One name, not a list.
icon string An icon shortcode, resolved as .icons/<value>.svg.
status string new and deprecated ship; others come from theme.extra.status.
subtitle string Rendered under the navigation entry. Material 9.6 and later.
hide string array navigation, toc, path, tags, footer, feedback.
tags string array Read by the tags plugin and added to the search index.
search object exclude and boost.
social object cards, cards_layout, cards_layout_options.
date date | object A post’s date, or a mapping requiring created.
authors, categories string array A post’s authors and categories.
draft, pin boolean Hold a post back; pin it to the top of a view.
readtime integer Overrides the computed reading time, in minutes.
slug string Overrides a post’s URL segment.
links array A post’s sidebar links, in nav shape.

hide is the field this schema exists for. Material decides what to hide by testing membership of the list, with "navigation" in page.meta.hide. It says nothing at all about an entry it does not recognise, so hide: [sidebar] builds cleanly and hides nothing. The six values are transcribed from the templates that test them, not from a documentation page, so the list is what the theme actually honours.

The rest of the value is in the typing. readtime, draft and pin go through the blog plugin’s own configuration validation, which refuses a quoted number or a quoted boolean outright. tags reaches a search plugin that checks isinstance(tags, list) and skips a bare string without a word. boost is copied into the search index exactly as written, so a quoted one ranks nothing.

A platform schema claims the keys your generator reads. A vocabulary claims the keys your team agreed on. They mostly do not overlap, so one run can hold a page to both and attribute each failure to the schema that raised it:

Terminal window
docmeta validate docs/ -s astro:starlight:0.41 -s diataxis:diataxis:1.0

title and description appear in several of these, and every definition agrees that they are strings, so stacking is safe.

docmeta.config.yaml
schemas:
- astro:starlight:0.41
- diataxis:diataxis:1.0