Metadata Schema
The frontmatter contract for every article in Frontend Engineering. The YAML block at the top of each file is machine-readable metadata: it powers search and social previews, drives the reading graph, and is mirrored into each domain's graph.json. This document is the authoritative schema — field names, types, allowed values, and validation.
One canonical spelling. The repository already ships a frontmatter schema used by
templates/article-template.md,scripts/validate-frontmatter.py, and everygraph.json. That schema is snake_case, and it is the law. This document formalizes it, adds two optional fields (version,authors), and maps the commonly-requested camelCase names onto it so no one invents a parallel vocabulary. Changing a field name is a breaking change to tooling and hundreds of files — do not do it casually.
Table of contents
- The schema
- Field reference
- Allowed values (enums)
- Complete example
- Mapping requested names to canonical fields
- Validation and the graph mirror
The schema
- Format: YAML, delimited by
---…---, the very first bytes of the file (no blank line before). - Case:
snake_casekeys. - Dates: ISO
YYYY-MM-DD, quoted. - Lists: YAML sequences; empty is
[](never omitted where the field is required). - Strings with punctuation (
:), and all dates, are quoted. - Every required field is present on every article; optional fields are omitted when unused (except required lists, which are
[]).
Field reference
| Field | Required | Type | Purpose |
|---|---|---|---|
title | yes | string | Human-readable Title Case. Matches the H1 and the graph.json title. |
slug | yes | string | Kebab-case filename without .md. Stable — never changes once published. |
description | yes | string | 150–160 char meta description; SEO snippet and social preview. Leads with the primary keyword. |
keywords | yes | string[] | Search terms and synonyms a reader would use to find this. |
part | yes | string | The numbered Part, e.g. 03 · Application Architecture. |
domain | yes | string | The domain folder's display name (the article's category). |
subcategory | yes | string | The topic group from the domain README. |
difficulty | yes | enum | Foundational | Intermediate | Advanced | Staff. |
reading_time_min | yes | number | Estimated minutes; matches graph.json. |
priority | yes | enum | Inherited from the Part: Critical | High | Medium. |
status | yes | enum | Planned | Draft | In Review | Published. |
canonical | yes | boolean | true if this file is the concept's one canonical home. |
last_reviewed | yes | date | ISO date of the last accuracy review. Drives the freshness and evergreen systems. |
prerequisites | yes | string[] | Read BEFORE this. Article titles; cross-domain as Article · Domain. |
related | yes | string[] | Closely connected article titles (see-also, undirected). |
next | yes | string[] | Read AFTER this — inverse of another article's prerequisites (≤5). Regenerated by scripts/build-links.py. |
alternatives | yes | string[] | Substitutes: other approaches to the same problem. [] if none. |
common_mistakes | yes | string[] | Links into the anti-pattern catalog (anti-patterns/README.md#<domain>) plus the article's own #common-mistakes anchor. |
frameworks | yes | string[] | Frameworks the article assumes; [] if agnostic. Name versions where behavior depends on them. |
version | new, optional | string | Content version of this article, MAJOR.MINOR (see evergreen). Bumped on a reviewed rewrite; omit until first publish. |
authors | new, optional | string[] | GitHub handles of significant contributors, for credit. Omit if using git history alone. |
references | optional | object[] | Optional structured mirror of the References section ({ title, url }), for tooling; the prose References section remains the source of truth. |
og_image | optional | string | Path under assets/ for the social/OG image. |
Notes on the two new fields. version and authors are additive and optional, so they do not disturb the existing validator (which checks only a required core). Adopt version when the evergreen policy versioning kicks in; use authors where credit matters beyond git blame.
Allowed values (enums)
difficulty:Foundational·Intermediate·Advanced·Staffpriority:Critical·High·Mediumstatus:Planned·Draft·In Review·Published(addDeprecatedandArchivedper the evergreen policy when an article leaves active service)canonical:true·falsepart: one of the nine canonical Part strings from the Knowledge Map (00 · Foundations…08 · Craft & Leadership).
Complete example
---
title: "Optimistic Updates in Data-Fetching Layers"
slug: optimistic-updates
description: "Optimistic updates apply a change to the UI before the server confirms it, trading correctness guarantees for latency. When to use them, and how to roll back safely."
keywords: ["optimistic updates", "optimistic UI", "mutation rollback", "server state"]
part: "03 · Application Architecture"
domain: "Data & Server State"
subcategory: "Mutations & Synchronization"
difficulty: "Advanced"
reading_time_min: 14
priority: "Critical"
status: "Published"
canonical: true
last_reviewed: "2026-07-24"
version: "1.2"
authors: ["ualiyou"]
prerequisites:
- "Server vs Client State"
- "Cache Invalidation Strategies"
- "Promises & Async Control Flow · JavaScript"
related:
- "Query Cache Design"
- "Error Boundaries for Data Layers"
next:
- "Conflict Resolution for Concurrent Mutations"
alternatives:
- "Pessimistic Updates"
- "Server-Driven UI Refetch"
common_mistakes:
- "anti-patterns/README.md#data-server-state"
- "#common-mistakes"
frameworks: ["react"]
references:
- { title: "TanStack Query — Optimistic Updates", url: "https://tanstack.com/query/latest/docs/framework/react/guides/optimistic-updates" }
og_image: "assets/optimistic-updates-sequence.svg"
---Mapping requested names to canonical fields
Planning documents and external requests sometimes use camelCase or shorter names. They map onto the canonical schema as follows — use the canonical (right) column in files:
| Requested name | Canonical field | Note |
|---|---|---|
summary | description | Same purpose: the 150–160 char meta description. |
category | domain | The article's category is its domain. |
readingTime | reading_time_min | Minutes, integer. |
lastReviewed | last_reviewed | ISO date. |
tags | keywords | Same list of search terms/synonyms. |
references | references (+ prose References) | Structured field optional; prose section required. |
version | version | Adopted as-is (new optional field). |
authors | authors | Adopted as-is (new optional field). |
status | status | Same. |
prerequisites / related | prerequisites / related | Same. |
There is intentionally no separate alternatives/next/common_mistakes alias — those are the repository's typed-relation names and must be used directly (see INTERNAL_LINKING.md and linking-rules.md).
Validation and the graph mirror
scripts/validate-frontmatter.pyruns in CI and requires the core keys. The frontmatter must also mirror the domain'sgraph.jsonfor the shared fields (title,slug,subcategory,order,difficulty,reading_time_min,prerequisites,related,next,alternatives,common_mistakes). The two are kept identical by hand and byscripts/build-links.py.- After editing prerequisites/alternatives: run
python3 scripts/build-links.py(refreshes inversenextedges), thenpython3 scripts/validate-links.py. Every edge must resolve to an existing node; the prerequisite graph stays acyclic. - Known discrepancy to fix (maintenance). The current validator checks for a key literally named
reading_time, while the template and this schema usereading_time_min. These should be reconciled toreading_time_minin the validator so the required-key check matches reality. This is tracked as a maintenance item inquality-metrics.md; until then, ensure both the validator's expectation and the file agree, and preferreading_time_minas canonical.
Next: article-quality.md — the sections this metadata describes · linking-rules.md — the typed relations in the list fields · naming-conventions.md — how slug is formed.