---
title: Serve docs and a blog from separate content roots
description: 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.
canonical_url: https://usepennington.net/how-to/discovery/multiple-sources/
sidecar_url: https://usepennington.net/how-to/discovery/multiple-sources.md
content_hash: sha256:66aa1437a4203cbf5f88d3cd60f7aec90cde4f46deb09171bd8b8fad42453d11
tokens: 1380
uid: how-to.discovery.multiple-sources
reading_time_minutes: 3
---

Guides
# 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](https://usepennington.net/tutorials/getting-started/first-page.md).

 
## Before you begin

 
 - A working Pennington site (see [Your first Pennington site](https://usepennington.net/tutorials/getting-started/first-page.md) if not).
 - The chosen host extension — `AddDocSite` versus bare `AddPennington` — and the reason for that choice ([What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md)).
 - Familiarity with `IFrontMatter` basics ([Define custom front-matter keys](https://usepennington.net/how-to/pages/front-matter.md)).
 
 
For a working DocSite multi-area setup, see [examples/DocSiteKitchenSinkExample](https://github.com/usepennington/pennington/tree/main/examples/DocSiteKitchenSinkExample). For the bare `AddPennington` chained-sources recipe, see [examples/MultipleSourcesExample](https://github.com/usepennington/pennington/tree/main/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.

 
```csharp:symbol,bodyonly
=>
[
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.

 
```csharp:symbol,bodyonly
=> 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

 
```csharp:symbol,bodyonly
md.ContentPath = "Content/docs";
md.BasePageUrl = "/docs";
md.SectionLabel = "Documentation";
```

 
### Register a second source with a different front-matter type

 
```csharp:symbol,bodyonly
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.

 
```csharp:symbol,bodyonly
md.ContentPath = "Content";
md.BasePageUrl = "/";
md.ExcludePaths = ["blog"];
```

 
## Verify

 
 - Run `dotnet run` and visit each source's `BasePageUrl`. 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.Title` in the generated navigation.
 
 
## Related

 
 - Reference: [PenningtonOptions.AddMarkdownContent<T>](https://usepennington.net/reference/api/pennington-options.md)
 - Reference: [DocSiteOptions.Areas and ContentArea](https://usepennington.net/reference/api/doc-site-options.md)
 - Background: [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md)
 - Extensibility: [Source content from outside the file system](https://usepennington.net/how-to/content-services/custom-content-service.md)
 
 
[Previous
                
                Version a DocSite](https://usepennington.net/how-to/versioning/docsite.md)[Next
                    
                Tune what the search box returns](https://usepennington.net/how-to/discovery/search.md)