URL: /reference/schema/frontmatter

---
title: Frontmatter
description: Per-page MDX frontmatter fields.
icon: "list-ordered"
---

# Frontmatter

Every `.mdx` file may declare frontmatter at the top:

```md
---
title: My page
description: One-line summary
icon: book
tag: Beta
---

Body starts here. Don't repeat the title as a `# Heading` — `title` already
renders as the page H1.
```

Frontmatter is parsed by `gray-matter` and validated against `@tanglydocs/schema`'s `FrontmatterSchema`. Validation is non-fatal: invalid fields surface as warnings, the page still renders.

## Recognized fields

<ParamField path="title" type="string">
  Page title. Falls back to a humanized slug if omitted (`guides/my-page` → "My Page"). Used in the H1, sidebar entry, browser tab, and OG title. Don't repeat the title as `# Heading` or `<h1>` in the body — `tangly dev` warns when it finds one.
</ParamField>

<ParamField path="sidebarTitle" type="string">
  Override the sidebar entry title only. The H1 still uses `title`.
</ParamField>

<ParamField path="description" type="string">
  Subtitle below the H1. Also used as the meta description and OG description when not overridden by `seo.description`.
</ParamField>

<ParamField path="icon" type="string">
  Lucide or Font Awesome icon name. Shown in the sidebar entry and any cards that link to this page. See [Icons](/reference/schema/icons) for the alias map.
</ParamField>

<ParamField path="tag" type="string">
  Small badge in the sidebar (e.g. "Beta", "New"). Style is theme-dependent.
</ParamField>

<ParamField path="api" type="string">
  Manual narrative for an OpenAPI endpoint. Tangly merges this Markdown with the auto-generated endpoint render so you can add prose around the auto-content.
</ParamField>

<ParamField path="openapi" type="string">
  Auto-render an OpenAPI endpoint. Format: `METHOD path` (e.g. `GET /users/{id}`). Pulls from the spec configured in `docs.json#api.openapi`.
</ParamField>

<ParamField path="openapi-schema" type="string">
  Render a single OpenAPI schema component. Format: `#/components/schemas/<Name>`.
</ParamField>

<ParamField path="keywords" type="string[]">
  Custom meta keywords for SEO.
</ParamField>

<ParamField path="noindex" type="boolean">
  Exclude from `sitemap.xml`, `llms.txt`, `llms-full.txt`, and the Pagefind search index. Page is still routable.
</ParamField>

<ParamField path="mode" type="enum" default="default">
  Page layout mode. One of:

  - `default` — sidebar + content + right-rail TOC.
  - `wide` — sidebar + content (no TOC).
  - `center` — centered content (no sidebar, no TOC).
  - `custom` — full-width content (no chrome).

  `wide`, `center`, and `custom` hide the right-rail TOC.
</ParamField>

<ParamField path="draft" type="boolean">
  Hidden in build, visible in dev with a "Draft" badge. Drafts are also excluded from search and sitemap. Build-time inclusion: `TANGLY_INCLUDE_DRAFTS=1 tangly build`.
</ParamField>

<ParamField path="template" type="string">
  Render through `templates/<name>.astro` instead of the default page shell. Resolution: `<userRoot>/templates/<name>.astro` → built-in template registry.
</ParamField>

<ParamField path="aiContext" type="string">
  Extra context injected into AI-assistant queries about this page. Reserved for the upcoming chat integration.
</ParamField>

<ParamField path="lastUpdated" type="boolean | string">
  Override the auto-derived last-updated stamp. `false` hides it on this page; an ISO date string (e.g. `2026-04-01`) overrides the git timestamp. Default is to inherit `footer.lastUpdated` from `docs.json`.
</ParamField>

<ParamField path="readingTime" type="boolean | number">
  Override the auto-computed reading-time. `false` hides it; a number (in minutes) overrides the word-count estimate. Inherits `appearance.readingTime` when omitted.
</ParamField>

<ParamField path="editUrl" type="string">
  Override the edit-on-source URL for this page. Useful when a single page is canonical-sourced from a different repo than the rest of the site.
</ParamField>

<ParamField path="glossary" type="boolean" default="true">
  Disable glossary auto-linking on this page. Set to `false` to skip term highlighting (typically on the glossary page itself).
</ParamField>

```md
---
title: Release notes
lastUpdated: false
readingTime: 3
editUrl: https://github.com/owner/notes/edit/main/RELEASES.md
glossary: false
---
```

<ParamField path="seo" type="object">
  Per-page SEO override.

  - `title: string` — overrides the OG/meta title.
  - `description: string` — overrides the meta description.
  - `ogImage: string` — custom Open Graph image URL.
</ParamField>

## Custom fields

`FrontmatterSchema` uses `passthrough()` — unknown fields are preserved and forwarded to the active template via `frontmatter`. This is how custom landing-page templates consume `hero`, `cta`, `headline`, etc.

```md
---
title: Welcome
template: landing
hero:
  headline: Build faster
  subheadline: Markdown in, deployed site out
cta:
  label: Start now
  href: /quickstart
---
```

The `landing` template reads `frontmatter.hero` and `frontmatter.cta` directly.

## Strict parsing

```ts
import { parseFrontmatter, safeParseFrontmatter } from "@tanglydocs/schema";

const fm = parseFrontmatter(rawObject);
const result = safeParseFrontmatter(rawObject);
```
