Skip to content

Built-in Docusaurus schemas

docmeta ships the front matter contract of Docusaurus 3.10 as three built-in schemas, one per content plugin:

Id Plugin Fields Upstream reference
docusaurus:docs:3.10 @docusaurus/plugin-content-docs 25 Docs front matter
docusaurus:blog:3.10 @docusaurus/plugin-content-blog 20 Blog front matter
docusaurus:pages:3.10 @docusaurus/plugin-content-pages 9 Pages front matter
Property Value
Dialect Draft 2020-12
Additional properties Allowed (additionalProperties: true)
Required fields None, in any of the three
Reference kind builtin
On by default No — see turning one on

Docusaurus marks no front matter field as required in any of the three plugins. A page with an empty --- block builds fine. These schemas mirror that: they constrain the shape of every field the plugins document, and demand none of them.

That makes them the opposite of the taxonomy schemas, which require their key. Turning a Docusaurus schema on cannot fail a page that was already building — it can only catch a value your site would have rejected, or silently mishandled, later.

Why check what Docusaurus already validates

Section titled “Why check what Docusaurus already validates”

Docusaurus validates its own front matter at build time, so these schemas are not a substitute for it. They earn their place three ways:

  • One report instead of one failure. A Docusaurus build stops at the first bad file. docmeta validate reports every offending page in the docs set in one run, with a line number for each.
  • Before a build, not during one. Validation needs no site config, no install of Docusaurus, and no build step, so it runs in seconds on a pull request that touches ten files.
  • Alongside your own standard. These schemas claim neither type nor action, so they compose with any of the taxonomy vocabularies. One command holds a page to the generator’s contract and your docs set’s conventions, attributing each failure to the schema that raised it. (Stacking with google:okf:0.1 is the one exception — both define tags, and their definitions disagree.)
Field Type Constraint
id string
title string may be empty
description string may be empty
slug string
sidebar_label string
sidebar_position number
sidebar_class_name string
sidebar_key string
sidebar_custom_props object
displayed_sidebar string or null
pagination_label string
pagination_next string or null
pagination_prev string or null
hide_title boolean
hide_table_of_contents boolean
toc_min_heading_level number 2–6
toc_max_heading_level number 2–6
parse_number_prefixes boolean
custom_edit_url string or null uri-reference
keywords array of string
image string uri-reference
tags array string, or object with label and permalink
draft boolean not both with unlisted
unlisted boolean not both with draft
last_update object author and/or date, at least one, nothing else

sidebar_position is a number. Quoting it makes it a string, and Docusaurus rejects it. This is the most common front matter mistake these schemas catch:

✗ docs/install.md
/sidebar_position must be number (line 3) [docusaurus:docs:3.10]

draft and unlisted are mutually exclusive. Setting both to true is the one cross-field rule Docusaurus enforces, and the schemas encode it. Either flag on its own is fine. Because JSON Schema expresses this as a conditional, it reports twice — once on the field to change, once on the rule as a whole:

✗ docs/install.md
/unlisted must be equal to constant (line 4) [docusaurus:docs:3.10]
(root) must match "then" schema (line 1) [docusaurus:docs:3.10]

Read the first line: drop unlisted (or draft) and both clear.

last_update takes author, date, or both — and nothing else. It is the only place the schemas forbid unknown keys, because a misspelled autor there is silently dropped rather than reported.

image and custom_edit_url are URI references. A site-root path like /img/social/card.png is legal, so these use uri-reference rather than uri, which would wrongly reject every relative path.

Tag objects need both halves. A tag is either a plain string or an object carrying label and permalink. Half an object fails.

  • toc_min_heading_leveltoc_max_heading_level. Docusaurus enforces the relationship between the two; JSON Schema cannot express a comparison between sibling fields without a non-portable extension. Each is range-checked to 2–6 on its own, and an inverted pair passes here and fails at build time.
  • Unknown keys. Docusaurus calls .unknown() on its own validators, so themes and plugins routinely add front matter of their own. Being stricter than Docusaurus would fail working sites, so these schemas allow extra keys.
  • Whether a reference resolves. pagination_next, displayed_sidebar, and authors are checked for shape, not for whether the id, sidebar, or authors.yml entry they name exists.

A Docusaurus site has three content roots with three different contracts, so config overrides are the natural fit:

docmeta.config.yaml
paths:
- docs
- blog
- src/pages
overrides:
- files: "docs/**"
schemas:
- docusaurus:docs:3.10
- diataxis:diataxis:1.0
- files: "blog/**"
schemas:
- docusaurus:blog:3.10
- files: "src/pages/**"
schemas:
- docusaurus:pages:3.10

The first matching override wins, so order them from most to least specific. For a one-off run, pass the id directly:

Terminal window
docmeta validate docs/ -s docusaurus:docs:3.10

The version segment is the Docusaurus minor release the contract was transcribed from, because that is where fields are added — sidebar_key is a recent arrival. A new minor arrives as a new id rather than a change to docusaurus:docs:3.10, so upgrading docmeta never retightens a check you already passed. Pin the id matching the Docusaurus you run, and move it when you upgrade.