Architecture
Page types
Bolt has exactly two page types — PHP and Markdown. The framework tells them apart by file extension alone; everything else is convention.
Two page types
A page in Bolt is just a file inside the pages/ directory, and the framework cares about exactly one thing when it loads that file: the file extension. There are only two page types.
| Extension | How content is produced | Best for |
|---|---|---|
.php |
The file is executed. It sets $page['config'] and builds $page['content'] itself. |
Anything dynamic — logic, loops, includes, forms, bespoke markup. |
.md |
Frontmatter becomes $page['config']; the body is rendered to HTML by Parsedown into $page['content']. |
Static prose — guides, articles, simple content pages. |
That is the whole type system — the extension decides how a page's content is produced. How a page looks is a separate concern, set by the layout it selects rather than by its type. The same two file types can produce a landing page, an article, or a docs page.
Whichever type a page is, it ends up as the same $page structure and flows through the same render pipeline: a header, a layout, and a footer, each chosen by a key in $page['config'].
How Bolt picks a file
Bolt uses file-based routing — the URL path maps straight to a file under pages/, with no route table to register. For a given path, it checks four candidates and the first match wins:
GET /pricing
1. pages/pricing.php ← PHP file
2. pages/pricing/index.php ← PHP page with its own resources
3. pages/pricing.md ← Markdown file
4. pages/pricing/index.md ← Markdown page with its own resources
Two consequences fall out of this order:
- PHP wins ties. If both
pricing.phpandpricing.mdexist, the PHP file is served. A Markdown page is used only when no PHP file resolves to the same URL. - The
indexforms are for pages with their own resources. Reach forpricing/index.php(orpricing/index.md) when a page ships files of its own — images, scripts,.css, a.pdfto link to, and so on. Its own folder keeps those assets beside it, addressable with relative paths; a page with no extra files is simpler as a singlepricing.phporpricing.md. This very page is organized as a folder for exactly that reason.
The home page (/) is resolved the same way, against pages/index.php then pages/index.md. For the full URL-sanitization rules, see Routing.
PHP pages
A PHP page owns the entire request. It runs whatever code it needs, then hands two things back to the renderer: a $page['config'] array and a $page['content'] string. The idiomatic pattern is to capture markup with output buffering:
<?php
$page['config']['title'] = 'Contact - Acme Club';
$page['config']['layout'] = 'canvas'; // optional — defaults to "default"
ob_start();
?>
<section class="py-20">
<h1>Get in touch</h1>
<p>We'd love to hear from you.</p>
</section>
<?php
$page['content'] = ob_get_clean();
?>
Because the file is plain PHP, a page can do anything PHP can: query a data store, loop over records, branch on the URL, post a form, or pull in shared partials with include (a pricing grid, a CTA, a callout). The ob_start() / ob_get_clean() pair simply collects everything echoed in between into $page['content']; the layout you selected then wraps it.
Configuration keys
Set these on $page['config']. Each maps a name to a file in the matching top-level directory, so the values are file names without the .php extension.
| Key | Purpose | Default |
|---|---|---|
title |
Text for the document <title> |
The request host |
header |
Which file in headers/ to render |
default |
layout |
Which file in layouts/ wraps the content |
default |
footer |
Which file in footers/ to render |
default |
A page may also set any custom key it likes (an article date, an author, a feature flag) for its layout to consume — the config array is just a bag of values passed through to the templates.
Markdown pages
A Markdown page carries no logic. It is frontmatter plus prose: Bolt reads the frontmatter into $page['config'], renders the body to HTML with Parsedown, and stores the result as $page['content']. It is the fastest way to add a route.
Title: Hello, Bolt
Layout: canvas
Author: Matt Todaro
---
## Welcome
This page is written in **Markdown**. Parsedown renders the body
to HTML and drops it into the layout named in the frontmatter.
- Bullet lists work
- So does `inline code`
---. The Key: Value lines come first, and a single --- closes the block. Start the file with --- and Bolt will treat your frontmatter as body text instead.
Frontmatter rules
- One
Key: Valueper line, before the first---. Everything after that---is the page body. - Keys are normalized — lowercased, with spaces turned into underscores.
Author URLbecomesauthor_url. - Values keep their colons, so
Author URL: https://example.comis parsed correctly. - Frontmatter is required. A Markdown file with no
---anywhere returns a404.
What a Markdown page cannot do is run code, branch, or include a partial. It picks its appearance with the Layout key and otherwise just supplies content. The moment you need any of that, reach for a PHP page.
Choosing between PHP and Markdown
- Reach for Markdown when a page is mostly text and needs no logic — it is quicker to write and impossible to break with a stray bug.
- Reach for PHP when you need data, conditionals, forms, shared includes, or hand-built markup.
- You can mix both freely in one site. Since both produce the same
$pageshape, switching a page's type later never changes its URL — and because PHP wins resolution, adding a.phpfile beside an existing.mdpage takes over immediately, so delete the now-unused.md.
Appearance is set by the layout
Page type governs how content is produced; how that content looks is a separate choice, made with the layout key. The same two file types drive every page on a site, each selecting the layout that fits:
- A landing or product page is typically a
.phpfile on thecanvaslayout, arranging full-width sections and a hero. - An article is any page — PHP or Markdown — with
Layoutset toarticle. - A docs page uses an article-style layout with navigation around it.
Choose a page's look with the layout key and the files in your site's layouts/ directory — see Layouts & templates for what each one provides.