Markdown and HTML Pages
Use .md and .html files as first-class page entries alongside .tsx — same routing conventions, different render path.
What this page covers
How .md and .html files in pages/ become routes. Covers the frontmatter keys recognised for .md pages, the v1 layout limitation, the static-asset contract for .html pages, and the SSG-only constraint shared by both.
zfb accepts seven page source extensions in total — .tsx, .ts, .jsx, .js (script pages, all bundled the same way) plus .mdx, .md, and .html (covered on this page). All seven follow the same file-system routing conventions under pages/ — pages/ and pages/ both produce the route /. What differs is the render path each extension takes. .mdx shares the MDX pipeline with .md and accepts the same frontmatter keys (see the .md pages section below). See Routing for the full accepted-extensions list.
.md pages
.md files placed in pages/ are compiled through the same MDX pipeline that drives content collections. The engine wraps the compiled body in a minimal HTML shell and writes the result to dist/ like any other page.
Frontmatter keys
Only two frontmatter keys are read for .md pages (v1 contract):
| Key | Type | Default | Effect |
|---|---|---|---|
title | string | URL slug | Sets the <title> element in the HTML shell. |
lang | string | "en" | Sets <html lang="…">. |
All other keys are silently ignored. There is no schema validation and no error for unknown keys — they are simply not surfaced in the rendered output.
---
title: About this project
lang: en
---
## What is this?
A short description of the project.The slug fallback for title is derived from the file stem — the last path segment without its extension. pages/ falls back to "about", and pages/ falls back to "intro" (not "docs/intro"). Use frontmatter title: when you need a more specific title.
Relative links
Relative Markdown links go through the standard MDX pipeline and are resolved relative to the source file.
v1 layout limitation
There is no layout system for .md pages in v1. A layout: key in frontmatter has no effect. The engine always produces a bare HTML document wrapping the MDX body — no <DefaultLayout>, no custom wrapper.
If you need a shared layout (navigation, header, footer), write a .tsx page instead and import the Markdown content as a component, or use a content collection.
No layout support for .md pages in v1
layout: frontmatter is ignored for .md page entries. Use .tsx if you need a layout wrapper around Markdown content.
SSG-only
.md page entries are SSG-only. They are not supported in SSR mode (Cloudflare Worker runtime). Use .tsx if you need server-side rendering.
.html pages
.html files in pages/ are copied verbatim to dist/ without any JavaScript rendering or post-processing. The engine treats them as static assets that happen to live under the routing tree.
Full-document requirement
The file must be a complete HTML document. It must start with <!doctype (case-insensitive) or <html. Bare HTML fragments (a <div> or a <p> block without wrapping structure) are out of scope for v1 and produce undefined output.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Static page</title>
</head>
<body>
<h1>Hello from a static .html page</h1>
</body>
</html>No post-processing
Because .html pages bypass the JS render pipeline entirely, the following do not apply:
Base-path rewriting — if your site uses a
baseprefix (e.g./), absolute href/src values in the file are not rewritten.pj/ site/ Link normalisation — the link normaliser that
.tsxand.mdpages go through is not run.Sitemap inclusion —
.htmlpage routes are not automatically added to a generatedsitemap.xml.
If any of those are needed, use .md or .tsx instead.
SSG-only
.html page entries are SSG-only. They are not supported in SSR mode.
Shared: SSG-only constraint
.md, .mdx, and .html pages are build-time (SSG) page sources. The dynamic-route skip gate only applies to .md and .html: bracketed .md / .html filenames are skipped with a warning because they cannot export paths(). A bracketed .mdx page is accepted by the scanner and can use the MDX module export surface for paths(). Static (non-parameterised) .md, .mdx, and .html page paths work correctly.
Choosing the right extension
| Situation | Recommended extension |
|---|---|
| Rich JSX page with a layout | .tsx |
| Simple content-only page, no shared layout needed | .md |
| Pre-authored static HTML file that needs no processing | .html |
| Page that contributes to sitemap or uses base-path | .tsx or .md |
| Server-side rendered page | .tsx |
See also
Routing — the full file-to-route mapping table.
Frontmatter — the unified frontmatter contract for
.tsxpages (includes TSX literal-only rules and output-extension precedence).Non-HTML Pages — emit XML, JSON, or plain text from
.tsxpages.Content Collections — the
getCollection()API for.md/.mdxfiles undercontent/.