Bolt CMS Docs
Sign in

Architecture

Routing

How Bolt CMS maps URLs to files using file-based routing, path sanitization, and automatic resolution.

How URLs Map to Files

Bolt CMS uses file-based routing. The URL path directly corresponds to a file or directory inside the pages/ folder. There is no route configuration file and no route registration step.

When a request comes in, Bolt strips the base path, sanitizes the URL, and looks for a matching file. If it finds one, the file is loaded. If not, a 404 is returned.

Resolution Priority

For a given URL path, Bolt checks for a matching file in this order:

  1. pages/{path}.php — direct PHP file match
  2. pages/{path}/index.php — directory with index file

The first match wins. If neither exists, Bolt sends a 404 Not Found response and exits.

Before the 404, resolution also falls back to any installed extensions. Core is always checked first, and a bare URL never serves an extension's page outright: if exactly one extension provides the route, Bolt redirects to its explicit /<slug>/{path} form; if two or more do, it returns a disambiguation page instead of guessing.

For sites that also support Markdown, the full resolution chain is:

  1. pages/{path}.php — direct PHP file
  2. pages/{path}/index.php — directory with PHP index
  3. pages/{path}.md — direct Markdown file
  4. pages/{path}/index.md — directory with Markdown index

Path Sanitization

Before attempting file resolution, Bolt sanitizes the incoming URL to prevent directory traversal and normalize the path:

  1. Query parameters stripped — everything after ? is removed.
  2. Fragment identifiers stripped — everything after # is removed.
  3. Leading and trailing slashes trimmed.
  4. Consecutive slashes collapsed// becomes /.
  5. Segments lowercased — URLs are case-insensitive.
  6. Non-alphanumeric characters removed — only letters, numbers, and hyphens survive in each segment.
// Sanitization in practice
$path = explode('?', $request_URI)[0];   // strip query
$path = explode('#', $path)[0];          // strip fragment
$path = rtrim(ltrim($path, '/'), '/');    // trim slashes
$path = preg_replace('/\/+/', '/', $path); // collapse slashes

$segments = explode('/', $path);
$segments = array_map('strtolower', array_map('trim', $segments));
$segments = array_map(function ($s) {
    return preg_replace('/[^a-zA-Z0-9-]/', '', $s);
}, $segments);
$path = implode('/', $segments);

The $page Array

Every page file receives the $page array and is expected to populate it. The array has two top-level keys:

$page['config']

Key Type Purpose
title string Browser tab title (<title> tag).
description string Meta description for SEO.
keywords string Meta keywords (comma-separated).
header string Which header file to load (default: 'default').
layout string Which layout file to load (default: 'default').
footer string Which footer file to load (default: 'default').
pageTitle string The H1 heading rendered by the layout.
pageDescription string Subtitle text rendered below the H1.

$page['content']

A string of HTML captured via output buffering. The layout template receives this and decides where to place it in the page structure.

Home Page Routing

The root URL (/) is a special case. Instead of sanitizing the path and resolving a file, Bolt directly loads pages/index.php:

if ($request_URI !== '/') {
    // ... sanitize and resolve path
} else {
    require(__DIR__ . '/pages/index.php');
}

This means pages/index.php always serves your home page. You cannot override this behavior.

404 Handling

If no matching file is found after the resolution chain, Bolt sends a 404 header and exits immediately:

header('HTTP/1.0 404 Not Found');
exit;

There is no built-in 404 page template. To show a custom 404 page, you would add a fallback require before the exit call to load a custom error page file.

Markdown Pages

If your site supports Markdown pages, files ending in .md are processed with frontmatter parsing. Frontmatter is defined between triple-dash delimiters at the top of the file:

---
title: About Us
description: Learn more about our team.
layout: default
---

# About Us

This is a Markdown page. It supports **bold**, *italic*, [links](https://example.com), and all standard Markdown syntax.

The frontmatter values are merged into $page['config']. The Markdown body is parsed into HTML (using a library like Parsedown) and assigned to $page['content'].

Example Routes

URL Resolved File
/ pages/index.php
/about pages/about.php or pages/about/index.php
/docs pages/docs.php or pages/docs/index.php
/docs/getting-started pages/docs/getting-started.php or pages/docs/getting-started/index.php
/blog/my-post pages/blog/my-post.php or pages/blog/my-post/index.php
/ABOUT pages/about.php (lowercased during sanitization)
/about?ref=home pages/about.php (query params stripped)
/does-not-exist 404 (no matching file)
Installation API routing