Serve docs and a blog from separate content roots
Register more than one markdown root — either as DocSite areas or as chained AddMarkdownContent calls on a bare Pennington host — and keep them from overlapping.
When one markdown tree needs more than one content root — a /docs/ section alongside a separate /blog/ section, or a catch-all root paired with a specialized subtree — registering multiple content sources is the answer. The right recipe depends on the host: AddDocSite supports multiple folder-scoped sub-trees through ContentArea entries on a single DocSiteFrontMatter pipeline; bare AddPennington allows any number of chained AddMarkdownContent<T> calls with independent front-matter types. For a first site, start with Serve markdown through Blazor Pages.
Before you begin
- A working Pennington site (see Your first Pennington site if not).
- The chosen host extension —
AddDocSiteversus bareAddPennington— and the reason for that choice (What the DocSite and BlogSite templates wire for you). - Familiarity with
IFrontMatterbasics (Define custom front-matter keys).
For a working DocSite multi-area setup, see examples/DocSiteKitchenSinkExample. For the bare AddPennington chained-sources recipe, see examples/MultipleSourcesExample.
Split a DocSite into areas
AddDocSite owns exactly one markdown pipeline keyed on DocSiteFrontMatter. To split that pipeline into folder-scoped sub-trees, populate DocSiteOptions.Areas with one ContentArea per slug — each slug becomes both the URL prefix and the top-level folder under ContentRootPath.
Declare the areas
Build the ContentArea list — one entry per slug, where the slug is both the URL prefix and the top-level content folder.
=>
[
new ContentArea("Main", "main"),
new ContentArea("API", "api"),
]
Wire the areas onto DocSiteOptions
Assign that list to DocSiteOptions.Areas so the single DocSiteFrontMatter pipeline discovers each folder as its own sub-tree.
=> new()
{
SiteTitle = "Kitchen Sink Docs",
SiteDescription = "A wide-surface DocSite example that backs eighteen how-to pages.",
GitHubUrl = "https://github.com/usepennington/pennington",
CanonicalBaseUrl = "https://example.com/",
HeaderContent = """<a href="/" class="font-bold">Kitchen Sink Docs</a>""",
FooterContent = BuildFooter(),
ColorScheme = BuildColorScheme(),
DisplayFontFamily = "'DocSiteKitchenSinkDisplay', system-ui, sans-serif",
BodyFontFamily = "'DocSiteKitchenSinkBody', system-ui, sans-serif",
FontPreloads = BuildFontPreloads(),
ExtraStyles = BuildExtraStyles(),
ConfigureLocalization = ConfigureLocalization,
ConfigurePennington = RegisterApiSource,
Areas = BuildAreas(),
}
Chain AddMarkdownContent on a bare host
On bare AddPennington, call AddMarkdownContent<TFrontMatter> once per source. Each call accepts its own ContentPath, BasePageUrl, and optional SectionLabel. Front-matter types can differ between sources.
Register the first source
md.ContentPath = "Content/docs";
md.BasePageUrl = "/docs";
md.SectionLabel = "Documentation";
Register a second source with a different front-matter type
md.ContentPath = "Content/blog";
md.BasePageUrl = "/blog";
md.SectionLabel = "Blog";
Carve out an overlapping subtree with ExcludePaths
When one source's ContentPath is a parent of another's, Pennington emits an overlap warning at startup because both pipelines would discover the inner tree and produce conflicting outputs. Adding ExcludePaths on the broader source gives the specialized source exclusive ownership of that subtree.
md.ContentPath = "Content";
md.BasePageUrl = "/";
md.ExcludePaths = ["blog"];
Verify
- Run
dotnet runand visit each source'sBasePageUrl. Pages render under both prefixes. - Startup logs contain no
Markdown content source rooted at '…' overlaps…warnings, or — when an overlap is intentional — the warning text names the subtree set aside for exclusion. - Each source's pages appear under the correct
SectionLabel/ContentArea.Titlein the generated navigation.
Related
- Reference:
PenningtonOptions.AddMarkdownContent<T> - Reference:
DocSiteOptions.AreasandContentArea - Background: What the DocSite and BlogSite templates wire for you
- Extensibility: Source content from outside the file system