Navigation

How the navigation tree is generated from your directory structure.

content.navigation() turns the flat list of documents in the manifest into a nested tree that mirrors your directory structure.

From directories to a tree

Each directory becomes a group, each Markdown file becomes an item inside it. Given this source:

content/
  index.md
  1.getting-started/
    1.installation.md
    2.configuration.md
  2.concepts/
    .navigation.yml
    index.md
    1.how-it-works.md

calling await content.navigation() returns:

[
  { title: 'Home', path: '/' },
  {
    title: 'Getting Started',      // generated from the directory name
    path: '/getting-started',
    page: false,                   // no index.md, unlinked group
    children: [
      { title: 'Installation', path: '/getting-started/installation' },
      { title: 'Configuration', path: '/getting-started/configuration' },
    ],
  },
  {
    title: 'Core concepts',        // from .navigation.yml
    path: '/concepts',             // links to its index.md
    children: [
      { title: 'Concepts', path: '/concepts' },
      { title: 'How it works', path: '/concepts/how-it-works' },
    ],
  },
]

Each entry is a NavigationItem:

interface NavigationItem {
  title: string            // from frontmatter (or generated for directories)
  description?: string     // frontmatter description
  path: string             // public URL path, e.g. '/getting-started/installation'
  children?: NavigationItem[]
  page?: false             // directory group with no linkable page
  [key: string]: unknown   // extra fields from `navigation` overrides
}

Ordering with numeric prefixes

Items are sorted by their file and directory names with natural numeric collation, so you order pages by prefixing them with <number>.:

1.getting-started/   → first
2.concepts/          → second
10.advanced/         → tenth (not between 1 and 2)

Prefixes affect ordering only — they are stripped from public paths, so 1.getting-started/2.configuration.md is served at /getting-started/configuration. Files without a prefix sort alphabetically. Version-like segments such as 1.2.x are preserved as-is in the URL.

Titles

A navigation item's title is resolved in order:

  1. navigation.title in the page's frontmatter.
  2. title in the page's frontmatter.
  3. For directories without a configured title, a title generated from the directory name: getting-startedGetting Started.

Index files

An index.md (or 3.index.md — the prefix still orders it) represents the directory itself:

  • The root index.md becomes the / entry.
  • A directory's index.md is listed inside that directory's children, and the directory node links to it.
  • A directory without an index page still appears as a group, marked with page: false, so you can render it as an unlinked heading.

Customizing with navigation frontmatter

The navigation key in a page's frontmatter controls how it appears in the tree:

1.installation.md
---
title: Installation
navigation:
  title: Install       # shown in the nav instead of `title`
  icon: i-lucide-download
---

Every key inside navigation is copied onto the item, so custom fields like icon or badge are available when rendering.

Set it to false to hide a page from navigation entirely:

drafts.md
---
navigation: false
---

The page is only removed from the tree — it still resolves through get() and list(). If a directory's index page opts out, the directory survives as an unlinked group (page: false); if the directory itself opts out (see below), the whole subtree is dropped and no empty ancestors are left behind.

Directory metadata with .navigation.yml

A directory can carry its own navigation metadata in a .navigation.yml file. Its navigation key is merged onto the directory's node the same way page frontmatter is:

2.concepts/.navigation.yml
navigation:
  title: Core concepts
  icon: i-lucide-lightbulb

Use navigation: false in a .navigation.yml to hide an entire directory from the tree.

The navigation tree is derived from the manifest, so it is versioned with your content: reading at a different commit through a source ref yields that snapshot's navigation.