You can keep one content directory and build separate sites for any configured facet: audience, product, area, subarea, or a custom facet such as region. Each entry config can have its own origin, base path, branding, navigation, and output directory. A developer portal is one example; the same workflow applies to an operations site, a product site, or regional resources.
Share the base configuration
Keep entry configs beside the base file so they resolve contentDir from the same directory:
resources/
base.yaml
docs.config.yaml
developers.config.yaml
europe.config.yaml
content/
home.md
api.md
operations.md
Start with Shoalrun installed in your project. The base declares the content, publication, and available facet choices:
schemaVersion: 1
site:
title: Acme resources
contentDir: content
publications:
defaults: { channel: production, version: current, language: en }
channels:
production: { pathPrefix: "" }
versions:
current: { pathPrefix: "" }
enabled:
- { channel: production, version: current }
frontmatter:
defaults:
type: guide
channel: production
version: current
access: { policy: public }
readerFilters:
facets:
audience:
label: Audience
options: { developer: Developers, operator: Operators }
region:
label: Region
options: { eu: Europe, us: United States }
Each page needs its ordinary identity fields and the facet values for the sites that should receive it. This overview belongs to both audiences and both regions:
---
id: guide.home
title: Resource overview
summary: Shared setup for all resource sites.
slug: /
audiences: [developer, operator]
readerFilters: { region: [eu, us] }
---
Give content/api.md the ID guide.api, a unique slug such as /api-requests, audiences: [developer], and readerFilters: { region: [us] }. Give content/operations.md the ID guide.operations, slug /operations, audiences: [operator], and readerFilters: { region: [eu] }. Add a title, summary, and body to both files. Link either page to the overview with [Shared setup](doc:guide.home).
The audience facet reads the page's audiences field. Configured product, area, and subarea facets read their corresponding category fields. Other facets use page-level readerFilters. Resolved readerFilters.typeDefaults also participate. See reader views for these marks.
Select the pages for each site
The main site omits contentFilter and publishes all otherwise eligible pages:
extends: [./base.yaml]
site:
origin: https://docs.example.com
navigation:
- { id: home, doc: guide.home }
- { id: api, doc: guide.api }
- { id: operations, doc: guide.operations }
A developer site selects the audience facet and supplies navigation for its selected pages:
extends: [./base.yaml]
site:
title: Acme developer resources
origin: https://developers.example.com
contentFilter: { audience: [developer] }
navigation:
- { id: home, doc: guide.home }
- { id: api, doc: guide.api }
A regional site selects the custom region facet independently of audience:
extends: [./base.yaml]
site:
title: Acme Europe resources
origin: https://eu.example.com
basePath: /resources
contentFilter: { region: [eu] }
navigation:
- { id: home, doc: guide.home }
- { id: operations, doc: guide.operations }
Every selected facet must match. Choices within one facet are alternatives: { audience: [developer, operator], region: [eu] } requires either audience and the European region. A page without a mark for a selected facet is excluded. Mark shared pages with all applicable values rather than leaving them unmarked. Unknown facets or choices, empty selections, and selections with no published pages fail the build.
The selector does not rewrite publication metadata. Public access, enabled publications, and language still determine eligibility. Keep explicit navigation and page links within the selected set; missing targets fail validation rather than copying excluded pages into the output. Separate entry configs can replace inherited navigation lists.
Build and check each output
From resources/, build each site into its own directory:
shoalrun build docs.config.yaml dist/main
shoalrun build developers.config.yaml dist/developers
shoalrun build europe.config.yaml dist/europe
Check each output's documents.json for its page IDs and routes. The main site contains all three pages. The developer site contains the overview and API guide. The European site contains the overview and operations guide beneath /resources. Inspect HTML, Markdown, search indexes, llms.min.txt, and the sitemap to confirm that excluded pages have no published entries or files. The runnable faceted-sites example ships with the framework's example configurations.
Deploy each output separately to its configured host. Building one site does not update the others. After editing shared content, rebuild and deploy every affected site. Keep output directories separate from sources and from one another because a successful build replaces its output directory.
Selection applies to whole authored and generated pages before rendering. A selected page retains its complete body, including reader-marked sections in HTML and Markdown. Browser reader controls cannot restore excluded pages. Section variants can use publication blocks where the sites also have distinct publications.
Configure API sources and operation selection separately. A published OpenAPI source may contain operations beyond the selected reference pages. Generated references use their resolved facet marks, including readerFilters.typeDefaults. This setting is a page publication selector, not authorization for private content; protect private deployments at the host.