Folder configuration
Blazorade Scraibe supports folder-level .config.json files so you can define machine-readable settings that control publish-time behavior. Their effects are visible at runtime through generated output files, but .config.json itself is not read by the running site. Configuration files are metadata, not content, so they are read by the pipeline but never published as pages.
What .config.json is used for
A .config.json file can define site-level and folder-level settings, such as default layout and excluded content paths. The key behavior is inheritance: settings can apply to only one folder or flow to descendants.
Configuration files are never emitted as website artifacts:
- They do not generate HTML pages.
- They are not copied as static assets.
- They are not treated as alternate Markdown content.
File format
A .config.json file is a single JSON object with two optional objects:
local: applies only to the folder where the file exists.scoped: applies to the folder and all descendant folders.
{
"local": {
"setting1": "value1"
},
"scoped": {
"setting2": "value2"
}
}
Rules:
localandscopedare optional.- Empty config files are valid if the root is an object, such as
{}. - If present,
localandscopedmust be JSON objects. - The same key cannot appear in both
localandscopedwithin one file. - Values can be any valid JSON value.
Inheritance and precedence
When resolving effective settings for a page or folder, the pipeline walks from repository root to the target folder.
At each folder level:
- Apply that folder's
scopedkeys. - After walking the full chain, apply
localfrom the closest folder that has a.config.jsonfile.
Nearest definition wins by key.
Practical consequences:
- Child
scopedoverrides parentscoped. - Child
localoverrides inheritedscopedfor that folder. - If a folder has no
.config.json, the nearest parent.config.jsonprovides the effectivelocallayer. localin one folder does not block descendantscopedevaluation.
This means you do not need a .config.json in every folder for settings to apply.
Example
Root content config:
{
"local": {
"nav_mode": "compact-root"
},
"scoped": {
"page_layout": "docs",
"nav_mode": "full"
}
}
Nested docs config:
{
"local": {
"nav_mode": "compact"
}
}
Effective values:
- Files directly in
/content/:page_layout=docs,nav_mode=compact-root - Files directly in
/content/scraibe-docs/:page_layout=docs,nav_mode=compact - Files in
/content/scraibe-docs/shortcodes/:page_layout=docs,nav_mode=full
If /tools has no .config.json, the repository-root .config.json still applies there: all inherited scoped keys apply, and the root local keys are treated as the effective local layer for /tools.
Common framework keys
These keys are currently used by the framework:
scraibe.site.displayName: Human-readable site name used in generated UI and metadata. This value is used by generated navigation branding and other site identity output.scraibe.site.appName: Technical app identifier used for project and namespace identity.scraibe.site.hostName: Host name used for canonical URLs and sitemap<loc>generation. See publishing.scraibe.site.webAppPath: Repository-relative path to the Blazor WebAssembly web app project.scraibe.site.componentLibraryPath: Repository-relative path to the component library project where shortcodes, layouts, and styling assets live.scraibe.layout.default: Default layout name when page frontmatter does not definelayout. See page layouts and content authoring.scraibe.publish.excludedContent: Array of content-relative paths that publish skips entirely. See publishing.scraibe.navigation.provider.default: Default navigation provider name when the active layout does not setx-provideron itsx-part="nav"slot. See page layouts and publishing.scraibe.navigation.children.depth: Number of descendant folder levels to include under navigation item children.0means no descendant folder expansion,1includes one level, and larger values include deeper nesting. See publishing.scraibe.navigation.context.pinned: Enables pinned navigation context from the folder where it is set.
Recommended placement at repository root:
- Put
scraibe.site.webAppPath,scraibe.site.componentLibraryPath, andscraibe.publish.excludedContentinlocal. - Put shared identity/layout defaults (
scraibe.site.displayName,scraibe.site.appName,scraibe.site.hostName,scraibe.layout.default) inscoped.
If frontmatter layout is missing on a page, publish resolves layout from scraibe.layout.default. If neither exists, publish fails with a clear error.
Navigation configuration keys
Navigation behavior is controlled by three primary keys that can be used together:
scraibe.navigation.provider.default: selects the navigation provider to render markup when the layout does not explicitly pick one.scraibe.navigation.children.depth: controls how many descendant folder levels are included in navigation item trees.scraibe.navigation.context.pinned: controls whether descendant pages keep using an ancestor folder as their navigation context.
In practice, use these keys as a set: choose the provider, choose how deep child links should go, then choose whether folder context should stay anchored. Provider rendering details still belong to the selected navigation provider implementation.
Pinned navigation context
Use scraibe.navigation.context.pinned to control whether a folder becomes the navigation context root for descendant pages.
true: Navigation context becomes sticky at the folder where the effectivetruevalue comes from.false: Explicitly breaks inherited sticky context for that branch.
In practice, sticky means pages can keep using an ancestor folder as their navigation context even when the page itself is deeper in the tree. Instead of switching context at every subfolder boundary, navigation stays anchored to the sticky folder until another sticky decision overrides it.
When a lower folder sets scraibe.navigation.context.pinned to false, it stops inheriting pinned context behavior from higher folders for that branch. From that point downward, navigation context falls back to the normal per-folder behavior unless that branch sets scraibe.navigation.context.pinned to true again.
local versus scoped semantics follow normal configuration inheritance rules:
scopedapplies to the folder and descendants until overridden.localfrom the nearest.config.jsonremains the effective local layer for the target folder resolution.
Example:
/content/.config.jsonsetsscoped.scraibe.navigation.context.pinned = true./content/docs/getting-started/intro.mduses/contentas navigation context because pinned context is inherited./content/docs/.config.jsonsetslocal.scraibe.navigation.context.pinned = false./content/docs/getting-started/intro.mdnow stops inheriting pinned context from/contentand uses normal folder context rules under/content/docs./content/docs/api/.config.jsoncan setscoped.scraibe.navigation.context.pinned = trueto start a new pinned context for/content/docs/apiand its descendants.
The publish pipeline only builds the navigation model context. Rendering details, including whether an up-link is shown, remain the responsibility of the selected navigation provider.
Troubleshooting
Typical validation failures are:
.config.jsonroot is not an object.localexists but is not an object.scopedexists but is not an object.- A key appears in both
localandscopedin the same file.
The publish pipeline reports file-path-based errors to help you locate and fix invalid configuration quickly.