Configuration reference
Complete reference for PreactPress site, theme, Markdown, build, and hook options.
Configuration lives in .preactpress/config.ts. A plain object works without imports; defineConfig adds type inference once PreactPress is installed.
import { defineConfig } from "@kamod-ch/preactpress/config";
export default defineConfig({
site: { title: "My docs", description: "Product documentation" },
});
Top-level options#
| Option | Purpose |
|---|---|
srcDir |
Content root, default . |
srcExclude |
Glob patterns that must not become pages |
outDir |
Static output directory, default dist |
cacheDir |
Incremental build cache directory |
cleanUrls |
Emit path/index.html when true |
rewrites |
Map public routes to existing content routes |
ignoreDeadLinks |
Boolean, glob list, or callback used by check |
mpa |
Remove client navigation from regular Markdown pages |
lastUpdatedGit |
Prefer git commit times for last-updated metadata |
theme |
Custom Preact layout module relative to .preactpress |
site |
Global title, description, language, URL, base, and title template |
locales |
Locale metadata and locale-specific theme settings |
themeConfig |
Default-theme navigation and page chrome |
markdown |
Markdown parser features |
head |
Global meta, link, and script tuples |
vite |
User Vite configuration merged into the internal config |
build |
Sitemap, robots, and feed output |
pageReady |
Built-in loading overlay while CSS becomes ready; false disables |
Page-ready preloader#
PreactPress injects a small inline preloader into every HTML document so the first paint does not flash unstyled content. Customize or disable it in config instead of editing HTML with transformHtml.
export default defineConfig({
// Disable the built-in preloader entirely
pageReady: false,
// Or customize the overlay
pageReady: {
preloader: '<img src="/brand-mark.svg" alt="" width="48" height="48" />',
fallbackMs: 3000,
probe: "--pp-bg", // CSS variable that must be set before reveal
},
});
preloader accepts either a full element with id="pp-preloader" or inner HTML only (wrapped automatically). The built-in spinner follows the default theme: it reacts to data-theme, the dark class, and prefers-color-scheme. Custom markup needs its own light/dark styles unless you reuse the pp-preloader-spinner class.
probe: false skips the CSS-variable check and waits for stylesheet links only.
Site metadata#
site: {
title: 'My docs',
description: 'Short summary for search and social previews',
lang: 'en',
url: 'https://example.com',
base: '/',
titleTemplate: ':title | :siteTitle'
}
Set site.url for canonical URLs, Open Graph, sitemap, robots, feeds, and locale alternates. Use site.base for subpath hosting.
Theme options#
| Option | Purpose |
|---|---|
logo |
URL or { light, dark } image pair |
labels |
Override localized UI labels |
nav |
Header links and nested dropdowns |
sidebar |
Global groups or path-prefix map |
outline |
Enable or choose heading levels |
search |
Local search or Algolia DocSearch |
socialLinks |
Built-in or custom SVG social icons |
tags |
Show or hide page tag chips |
footer |
Site footer text |
editLink |
Repository edit URL pattern using :path |
lastUpdated |
Show page timestamps |
Available label keys are skip, navigation, menu, closeMenu, search, filterPages, searchResults, previous, next, lastUpdated, onThisPage, and language.
Markdown options#
markdown: {
html: false,
linkify: true,
typographer: true,
emoji: true,
math: false
}
Math is opt-in because it adds MathJax processing. Raw HTML should remain disabled for untrusted content.
Build output#
build: {
sitemap: true,
robots: true,
feed: { limit: 20 }
}
Feed, sitemap, and robots output require site.url.
Hooks#
transformHead, transformPageData, and transformHtml run in development and production builds. buildEnd runs once after a successful production build. See Advanced APIs.
Page frontmatter#
Common fields include title, description, tags, image, type, draft, layout, hero, features, navbar, sidebar, aside, outline, footer, editLink, lastUpdated, titleTemplate, head, pageClass, isHome, and markdownStyles.
TypeScript types#
Import defineConfig from @kamod-ch/preactpress/config for typed site configuration with autocomplete on every supported option. The loader accepts a plain object or an async factory:
import { defineConfig } from "@kamod-ch/preactpress/config";
export default defineConfig(async () => ({
site: { title: "My docs", description: "Product documentation" },
}));
At build time PreactPress validates your config and resolves defaults into an internal ResolvedConfig object. User-facing options stay on UserConfig; internal modules consume the resolved shape only.
Core types#
| Type | Import | Purpose |
|---|---|---|
UserConfig |
@kamod-ch/preactpress/config |
Authoring shape in .preactpress/config.ts |
ResolvedConfig |
@kamod-ch/preactpress |
Fully resolved internal configuration |
defineConfig |
@kamod-ch/preactpress/config |
Preserve literal types and async factories |
SiteConfig remains available as a backward-compatible alias for ResolvedConfig.
Invalid or unknown options throw ConfigError with the option path, for example preactpress config: plugins[0].name: expected a non-empty string.
Extension options#
Most extension options are typed and validated today. Some are reserved for upcoming releases. versions, redirects, and check are active today.
| Option | Purpose | Build output |
|---|---|---|
versions |
Multi-version docs with version switcher, archived banners, and search/sitemap partitioning | Active |
plugins |
Typed plugin runtime with deterministic hook ordering | Active |
apiDocs |
TypeDoc integration settings; set false to disable |
Reserved |
openapi |
OpenAPI integration settings; set false to disable |
Reserved |
ai |
AI export settings (llmsTxt, llmsFullTxt, copyMarkdown, contextIndex) |
Active |
redirects |
HTTP redirects with validation, static HTML fallbacks, and _redirects export |
Active |
check |
preactpress check behavior (failOnWarnings, plugins) |
Active |
Use rewrites for in-site route aliases that share one page. Use redirects for HTTP redirects emitted at build time.
export default defineConfig({
site: { title: "My docs", description: "Product documentation", url: "https://example.com" },
redirects: {
"/old-guide": "/guide/new-guide",
"/api/button": "/components/button",
},
});
Array syntax supports explicit status codes:
redirects: [
{ from: "/old-guide", to: "/guide/new-guide", status: 301 },
{ from: "/temporary", to: "/guide/new-guide", status: 302 },
];
Advanced options control build outputs:
redirects: {
entries: {
"/old-guide": "/guide/new-guide",
},
generateHtmlFallbacks: true,
generateRedirectsFile: true,
}
PreactPress validates redirect sources and targets, rejects duplicate sources and redirect loops, and warns in preactpress check when an internal target route does not exist. Redirect source routes are excluded from search, sitemap, and orphan detection. Static HTML fallbacks use a canonical URL pointing at the final destination.
Build output includes:
- Static HTML pages at each redirect source (meta refresh +
location.replace,noindex) _redirectsfor Netlify and Cloudflare Pages (whengenerateRedirectsFileis enabled)preactpress-redirects.jsonwith resolved rules and adapter metadata
Documentation versioning#
Recommended content layout:
current/ # current version (unprefixed routes)
index.md
guide/
de/ # locale folders inside each version tree
versions/
1.0/ # archived snapshot at /versions/1.0/...
1.1/
export default defineConfig({
versions: {
current: "2.0",
aliases: { latest: "2.0" },
items: [
{ value: "2.0", label: "2.x", status: "current" },
{ value: "1.0", label: "1.x", status: "archived" },
],
labels: {
archivedBanner:
"You are viewing docs for {label}. See the {currentLabel} docs for the latest version.",
},
},
});
Snapshot the current tree into versions/<value>/ with:
preactpress version 1.2.0 --label "1.2"
preactpress version 1.2.0 --dry-run
Scope individual pages to specific versions with frontmatter:
versions: ["2.0"]
Combined locale + version URLs use the pattern /de/versions/1.0/guide/page. Canonical URLs for archived pages point to the equivalent current-version route when it exists.
export default defineConfig({
site: { title: "My docs", description: "Product documentation" },
versions: {
latest: { label: "Next" },
"2.0": { label: "v2.0", link: "/2.0/" },
},
plugins: [{ name: "my-plugin", enforce: "pre" }],
apiDocs: { tsconfig: "tsconfig.json", outDir: "api" },
openapi: { spec: "openapi.yaml", base: "/api" },
ai: {
llmsTxt: true,
llmsFullTxt: true,
copyMarkdown: true,
contextIndex: true,
},
check: { failOnWarnings: false, plugins: true },
});
Omitting an extension block keeps the resolved defaults: empty plugins, disabled apiDocs / openapi / ai, empty redirect rules, and check: { failOnWarnings: false, plugins: true }.
AI exports#
Set ai to enable static artifacts for LLM retrieval and AI coding tools. See AI-ready documentation for usage with Cursor, Claude Code, and similar tools.
export default defineConfig({
site: {
title: "My docs",
description: "Product documentation",
url: "https://docs.example.com",
},
ai: {
llmsTxt: true,
llmsFullTxt: true,
copyMarkdown: true,
contextIndex: true,
exclude: ["/404", "/draft/**"],
maxBundleBytes: 1_500_000,
},
});
Build output includes /llms.txt, /llms-full.txt, per-page *.md files, and /api/context.json when the corresponding flags are enabled. The default theme shows Copy page as Markdown when copyMarkdown is true.
Frontmatter and page metadata are described by PageFrontmatter from @kamod-ch/preactpress/shared or @kamod-ch/preactpress/config.
For blogs and magazines, optional content-model helpers are available:
import { createContentLoader } from "@kamod-ch/preactpress/config";
import { articleFromFrontmatter, type ArticlePost } from "@kamod-ch/preactpress/shared";
export default createContentLoader<ArticlePost[]>(["posts/*.md"], {
transform(items) {
return items.map((item) =>
articleFromFrontmatter({
route: item.route,
url: item.url,
title: item.title,
description: item.description,
frontmatter: item.frontmatter,
}),
);
},
});
Loader output is exposed on page.meta.contentData for the matching route.