Directory Configuration

2026-07-04

Directory-level configuration is written in the folders field: sites use __everkm/everkm.yaml; themes can preset defaults in everkm-theme.yaml (site overrides by path). For config, default_template, and overall ownership of the two files, see Site Configuration · Config Scope.

Subdirectory configuration is merged with inheritance from ancestor directories; deeper configurations override or append to shallower fields with the same name.

Since v0.17.0: The legacy per-directory index.yaml is deprecated and no longer read. Please migrate your configuration to everkm.yaml#folders.

Basic Example

# __everkm/everkm.yaml
folders:
  "/":
    hide_in_url: true
  "/docs/":
    template: book.html
    query:
      stack: true
    breadcrumbs:
      - title: "@i18n:nav.docs"
        url: /docs/
  "/blog/":
    template: list.html
    url_id_suffix: false

In templates, the merged query results are read via the global variable __qs; for breadcrumbs, see __breadcrumbs and nav_path.

Field Reference

FieldTypeDefaultDescription
url_slugstringdirectory name slugifiedCustom URL path segment; when explicitly set, the slug enters descendant article URL prefixes even if the directory has no index.md (see [[#url-generation
hide_in_urlboolfalseWhen set to true, this directory is excluded from URL path concatenation
templatestringDefault template path for pages under this directory
queryobjectKey-value pairs merged into __qs during rendering
breadcrumbsarrayArray of breadcrumb entries, each containing title and url; supports @i18n:<key>
hash_scatterboolfalseWhether to scatter article URLs into subdirectories by hash (aliases: hash_storage, storage_scatter)
url_id_suffixbooltrueWhen set to false, non-index page URLs use {slug}.html without appending -{id}

Merge Rules

Config Sources and Priority

Same as config and default_template: theme folders as base, site everkm.yaml#folders overrides by path key. For deep merge of config (recursive objects, array replace), see Site Configuration.

effective_folders[path] =
  everkm-theme.yaml#folders[path] (if present)
  → everkm.yaml#folders[path] non-empty fields extend override

On the same path key, if the site only sets template, theme preset fields like url_slug and url_id_suffix are still retained.

Theme developers preset routes and templates in everkm-theme.yaml; site operators only write deltas in everkm.yaml. See Theme Metadata.

Ancestor Chain Merge

For an article in a directory (e.g., /blog/2025/01/), merge along the ancestor chain (root → leaf) on effective_folders:

Ancestor chain: / → /blog/ → /blog/2025/ → /blog/2025/01/
merged = defaults
For each level in chain: if effective_folders[path] exists → merged.extend(...)
  • Child-level explicit configuration overrides parent-level fields with the same name
  • When a child level has no configuration, it inherits the merged ancestor result
  • Merging follows ancestor chain order, not key string length sorting

Merge Rules

  • "Home" is no longer automatically inserted at the beginning of the chain; if a home entry is needed, declare it in folders["/"].breadcrumbs yourself
  • When a subdirectory's breadcrumbs is non-empty, entries are appended to the end of the ancestor chain by directory depth, rather than replacing the ancestor configuration entirely
  • When a subdirectory does not specify breadcrumbs, it does not clear the already-merged breadcrumbs from ancestors
  • If no level has configuration, breadcrumbs are auto-generated based on the current page's URL path: each directory's index page appears in the breadcrumbs

The title field supports @i18n:<key> references. Only when the entry does not have url configured (or url is empty), a title of [[wikilink]] will be resolved as an inner link (i18n replacement happens first, then inner link evaluation), adopting the target page's title and URL.

folders:
  "/":
    breadcrumbs:
      - title: "@i18n:nav.home"
        url: ~/
  "/blog/":
    breadcrumbs:
      - title: "[[blog]]"
      - title: "@i18n:nav.blog"

URL Generation

Directory Path Concatenation

url_path = join(effective_slug at each level), skipping levels where hide_in_url == true
effective_slug = url_slug ?? slugify(directory segment name at this level)

Which directory segments enter the URL (either condition suffices):

  1. Explicit url_slug: that level has a non-empty url_slug in effective_folders[path] (including theme presets)
  2. Directory index chain: that level lies on the path from root to the deepest directory index.md (directory home); levels without url_slug use slugified directory names

Intermediate levels without explicit url_slug and without any directory index on the ancestor chain do not appear in URLs (disk directory names are not leaked). Content can live under deep paths like /blog/2025/ while /blog/ uses url_slug: posts to map publicly to /posts/....

url_slug bypass is evaluated per path key and does not inherit to child directories. When parent /blog/ sets url_slug: posts, child /blog/2025/ without slug and without index does not push posts again.

Example (no directory index):

# theme or site folders
"/blog/":
  url_slug: posts
Article pathLogical URL
/blog/2025/hello.md/posts/hello-{id}.html (or hello.html; see url_id_suffix)

If /blog/2025/ also has index.md, descendant URLs gain a /2025/ segment: /posts/2025/hello.html.

Filename Rules

ConditionURL FilenameExample
Directory index pageindex/blog/index.html
Normal page + url_id_suffix: true (default){slug}-{id}/blog/hello-abc123.html
Normal page + url_id_suffix: false{slug}/blog/hello.html

Combined Examples

Directory partition + short URLs:

folders:
  "/blog/":
    url_id_suffix: false
    hash_scatter: true
  • Logical URL: /blog/my-post.html
  • Export physical path: /blog/ab/cd/my-post.html (triggered by __hs=1)

Decouple disk layout from public routes (common with theme presets + small site overrides):

# everkm-theme.yaml
folders:
  "/":
    hide_in_url: true
  "/blog/":
    url_slug: posts
    template: list.html
    url_id_suffix: false

# everkm.yaml (optional)
folders:
  "/blog/2025/":
    template: archive.html
  • /blog/2025/hello.md/posts/hello.html (intermediate 2025 has no index and no slug, omitted from URL)

Navigation Functions and Inner Links

Book/document templates commonly use nav_tree, nav_path, and nav_indicator. If their from_file parameter is wrapped in [[...]], the same resolution rules as body inner links apply (case-insensitive, ambiguous links cause errors).

{{ nav_tree(from_file="[[./SUMMARY.md]]") | json_encode }}