Pages
How page collections work — frontmatter schema, layout assignment, and the catch-all page pattern.
Page Frontmatter
Every Markdown page starts with YAML frontmatter. The basePageSchema validates these fields:
content/pages/about.mdc
---
title: About Us
description: Our story and mission.
hero: true
image: /images/about-hero.jpg
links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/your-org
target: _blank
---
Page content goes here...
| Field | Type | Default | Description |
|---|---|---|---|
title | string | required | Page title (used in <h1>, meta, OG) |
description | string | — | Meta description and subtitle |
label | string | — | Short label for navigation and badges |
hero | boolean | true | Show hero section with title/description |
image | string | — | Hero or OG image path |
excerpt | string | — | Short summary for listings |
navigation | boolean | — | Include in navigation tree |
layout | string | — | Override layout (prefer route rules instead) |
links | array | — | Action links shown in hero/header |
Layout Assignment
Layouts are assigned through route rules in nuxt.config.ts, not in frontmatter:
nuxt.config.ts
routeRules: {
'/': { appLayout: 'landing' },
'/about': { appLayout: 'default' },
'/offers/**': { appLayout: 'article' },
'/docs/**': { appLayout: 'docs' },
}
Available layouts:
| Layout | Purpose |
|---|---|
landing | Minimal chrome, no hero — for landing pages with MDC sections |
default | Standard content page with optional hero |
article | Article format with back button, date, image |
docs | Three-panel layout with sidebar navigation and table of contents |
See Layouts for details on each layout.
How Pages Render
Foundry uses a single catch-all page ([...slug].vue) that delegates rendering to layouts:
- A URL hits the catch-all page
- The route rule determines which layout to use
- The layout calls
useContentPage().getPage()to fetch the content ContentRendererrenders the Markdown body- MDC components (like
::section-hero) are resolved from yourcomponents/directory
This means you never create .vue page files for content pages — you create Markdown files in content/pages/ and assign a layout via route rules.
Creating a New Page
- Create a Markdown file in
content/pages/:
content/pages/pricing.mdc
---
title: Pricing
description: Simple, transparent pricing.
---
Your pricing content here.
- Add a route rule for the layout:
nuxt.config.ts
routeRules: {
'/pricing': { appLayout: 'default' },
}
- The page is now live at
/pricing.