Skip to main content

Frontmatter API

import {
parseFrontmatter,
parseKeyValuePairs,
applyFrontmatter,
} from "@noxion/core";

Noxion supports per-post metadata overrides via frontmatter — a code block at the very top of a Notion page containing key: value pairs. This lets you set custom slugs, SEO titles, and other metadata from within Notion without changing your database schema.

See Notion Setup → Frontmatter overrides for user-facing documentation.


parseFrontmatter()

Extracts key: value pairs from the first code block of a Notion page.

Signature

function parseFrontmatter(
recordMap: ExtendedRecordMap,
pageId: string
): Record<string, string> | null

Parameters

ParameterTypeDescription
recordMapExtendedRecordMapThe full page data (from fetchPage() or from the database fetch)
pageIdstringThe page's block ID

Returns

Record<string, string> | null

  • A key-value map if a code block was found and parsed successfully
  • null if the first content block is not a code block (no frontmatter)

How it works

  1. Reads pageBlock.content (the array of child block IDs)
  2. If the array is empty or non-existent, returns null
  3. Reads the first child block
  4. If the block type is not "code", returns null
  5. Extracts the text content from the block's properties.title
  6. Calls parseKeyValuePairs() on the text content

Example

import { createNotionClient, fetchPage, parseFrontmatter } from "@noxion/core";

const notion = createNotionClient();
const recordMap = await fetchPage(notion, "abc123...");
const frontmatter = parseFrontmatter(recordMap, "abc123...");

// If the first code block contains:
// cleanUrl: /my-post
// title: Custom SEO Title
// description: A great description
//
// Then:
// frontmatter → { cleanUrl: "/my-post", title: "Custom SEO Title", description: "A great description" }
// Or:
// frontmatter → null (if no code block at the top)

parseKeyValuePairs()

Parses a multi-line string of key: value pairs into an object.

Signature

function parseKeyValuePairs(text: string): Record<string, string>

Parameters

ParameterTypeDescription
textstringMulti-line string to parse

Returns

Record<string, string> — parsed key-value pairs. Always returns an object (never null).

Parsing rules

RuleExample
Lines with key: value are parsedtitle: My Post{ title: "My Post" }
Lines starting with # are comments# this is ignored
Empty lines are ignored
Keys are trimmed of whitespace key : value{ key: "value" }
Values include everything after the first :url: https://example.com/path?a=b:c{ url: "https://example.com/path?a=b:c" }
Lines without : are ignoredjust some text

Example

import { parseKeyValuePairs } from "@noxion/core";

parseKeyValuePairs(`
cleanUrl: /my-custom-slug
title: My SEO-Optimized Title
# description: (draft — not included)
description: The published description
tags: react, typescript, web
floatFirstTOC: right
`);
// Returns:
// {
// cleanUrl: "/my-custom-slug",
// title: "My SEO-Optimized Title",
// description: "The published description",
// tags: "react, typescript, web",
// floatFirstTOC: "right",
// }

applyFrontmatter()

Applies frontmatter key-value pairs to a NoxionPage object (or subtype), mapping known keys to top-level fields and metadata while preserving all keys in page.frontmatter.

Signature

function applyFrontmatter<T extends NoxionPage>(
page: T,
frontmatter: Record<string, string>
): T

Parameters

ParameterTypeDescription
pageNoxionPageThe source page object
frontmatterRecord<string, string>Parsed frontmatter (from parseFrontmatter() or parseKeyValuePairs())

Returns

NoxionPage — a new page object with frontmatter overrides applied. The original object is not mutated.

Known key mappings

Frontmatter keyTarget fieldTransformation
cleanUrlslugLeading / is stripped: /my-postmy-post
slugslugLeading / is stripped
titletitleDirect replacement
descriptiondescriptionDirect replacement
tagsmetadata.tagsSplit by , and trimmed: "react, ts"["react", "ts"]
coverImagecoverImageDirect replacement
covercoverImageAlias for coverImage

All frontmatter keys (including unknown/custom ones) are preserved in page.frontmatter as a Record<string, string>. Unknown keys are copied into page.metadata.

Example

import { applyFrontmatter } from "@noxion/core";

const post = {
id: "abc123",
title: "Original Notion Title",
slug: "abc123", // Fallback: page ID
tags: [],
// ...
};

const frontmatter = {
cleanUrl: "/better-slug",
title: "SEO-Optimized Title",
tags: "react, typescript, tutorial",
myCustomKey: "some-value",
};

const updatedPost = applyFrontmatter(post, frontmatter);
// updatedPost.slug → "better-slug" (leading / stripped)
// updatedPost.title → "SEO-Optimized Title"
// updatedPost.metadata.tags → ["react", "typescript", "tutorial"]
// updatedPost.frontmatter → { cleanUrl: "/better-slug", title: "SEO-Optimized Title", tags: "react, typescript, tutorial", myCustomKey: "some-value" }

Custom frontmatter in your app

Unknown frontmatter keys are accessible via post.frontmatter:

// app/[slug]/page.tsx
const post = await getPostBySlug(slug);

// Check if this post should show comments
const showComments = post.frontmatter?.comments !== "false";

// Use a custom layout hint
const layoutHint = post.frontmatter?.layout ?? "default";