Content Model
pageflare can read structured markdown content from your repo and use it as the source of truth for what each page should expose to search engines, AI agents, and humans. Frontmatter on every page declares the title, description, canonical URL, schema.org type, publish dates, and more. A single site.yaml at the root carries brand defaults that apply everywhere.
The same content drives multiple outputs in one pipeline pass:
- HTML
<head>injection — title, meta description, canonical, robots, Open Graph, Twitter cards. - JSON-LD blocks — Organization, page-type (Article / BlogPosting / WebPage / Product / ProfilePage), BreadcrumbList, plus any custom overrides.
sitemap.xml— drafts excluded,lastmodfilled frompublish.updated.llms.txt/llms-full.txt— drafts excluded.
You author content in markdown once, and every downstream output stays in sync.
Directory layout
Section titled “Directory layout”pageflare looks for content under a content/ directory at the project root. Each subdirectory is a content type:
content/├── site.yaml # global brand + defaults + route patterns├── pages/ # standalone pages → WebPage by default│ ├── index.md # → /│ ├── about.md # → /about/│ └── legal/│ └── privacy.md # → /legal/privacy/├── posts/ # blog posts → BlogPosting by default│ ├── hello-world.md # → /blog/hello-world/│ └── deep-dive.md # → /blog/deep-dive/└── docs/ # documentation → WebPage by default └── getting-started/ └── installation.md # → /docs/getting-started/installation/Built-in content types
Section titled “Built-in content types”| Type | Default URL pattern | Default schema.org page type |
|---|---|---|
pages | /{rel-path}/ | WebPage |
posts | /blog/{slug}/ | BlogPosting |
docs | /docs/{rel-path}/ | WebPage |
index.md collapses to the directory’s URL (so pages/index.md → /, docs/getting-started/index.md → /docs/getting-started/).
Custom content types are allowed — register them under content.types in pageflare.jsonc with a URL pattern.
URL resolution precedence
Section titled “URL resolution precedence”slug:in frontmatter wins absolutely.slug: "/totally-custom/"overrides any pattern.- Route override in
site.yaml—routes.<type>.patternoverrides the built-in default. - Built-in default pattern for the content type.
Trailing slashes are always normalized.
site.yaml — global defaults
Section titled “site.yaml — global defaults”The content/site.yaml file declares site-wide brand identity and defaults. Most fields are optional, but site.name, site.url, and site.locale are required.
site: name: "Acme Docs" url: "https://acme.dev" locale: "en-US" default_og_image: "/content/assets/og-default.png" twitter_handle: "@acme"
brand: organization: name: "Acme Inc." url: "https://acme.dev" logo: "/content/assets/logos/acme-mark.svg" same_as: - "https://github.com/acme" - "https://x.com/acme"
defaults: seo: robots: "index,follow" twitter: card: "summary_large_image"
routes: posts: pattern: "/articles/{slug}/"| Field | Required | Description |
|---|---|---|
name | Yes | Display name of the site — used in og:site_name and as the default BlogPosting.publisher.name. |
url | Yes | Site base URL (no trailing slash). Used to absolutize canonical URLs and BreadcrumbList items. |
locale | Yes | BCP-47 locale, e.g. en-US, de-DE. Used in og:locale. |
default_og_image | No | Path or absolute URL — fallback for any page that doesn’t set seo.og.image. |
twitter_handle | No | Default twitter:site value. |
brand.organization PRO
Section titled “brand.organization ”When present, pageflare emits an Organization JSON-LD block on every page. This is what tells AI crawlers and Google’s Knowledge Graph what entity the site belongs to.
| Field | Required | Description |
|---|---|---|
name | Yes | Organization legal/display name. |
url | Yes | Organization homepage. Usually the same as site.url. |
logo | No | Logo URL — must be a square image per schema.org guidance. |
same_as | No | Array of canonical profile URLs (GitHub, X/Twitter, LinkedIn, Crunchbase). Strengthens entity linking. |
defaults
Section titled “defaults”Defaults fill in any field a page doesn’t explicitly set. They cascade — a page can override one field while inheriting the rest.
defaults.seo— same shape as the per-pageseo:block. Common use: a site-widerobots: "index,follow"and a default Twitter card style.
routes
Section titled “routes”Override the built-in URL pattern for a content type. Patterns understand two placeholders:
{slug}— the file stem (filename without.md).{rel-path}— the file’s path relative to the type directory, without extension.
Example: routes.posts.pattern: "/articles/{slug}/" makes content/posts/hello.md resolve to /articles/hello/ instead of /blog/hello/.
How content reaches the optimized output
Section titled “How content reaches the optimized output”The content pipeline runs once per page:
- Scan —
content/<type>/**/*.mdfiles are discovered, frontmatter parsed, URLs resolved. - Match — each HTML page found by the optimizer is matched against a content entry by URL.
- Inject — frontmatter drives
<head>SEO tags, JSON-LD blocks, and the canonical URL. - Filter — pages with
draft: trueare removed fromsitemap.xmlandllms.txt. - Date —
publish.updated(falling back topublish.date) fills<lastmod>insitemap.xml.
If a page has no matching content entry, it’s still optimized — pageflare just doesn’t inject anything that isn’t already in the HTML.
Related
Section titled “Related”- Frontmatter Reference — every field a page can set.
- JSON-LD — schema.org emission, page-type mapping, and overrides.
- Markdown for Agents —
llms.txtgeneration and edge markdown content negotiation.