Fumadocs page tree
Page URLs and the sidebar both derive from the content directory layout plus per-folder meta.json. This file covers the load-bearing rules and the traps; verify anything beyond it against the local checkout ~/repo/fumadocs — conventions in apps/docs/content/docs/headless/page-conventions.mdx, ground truth in packages/core/src/source/plugins/slugs.ts (slugs) and packages/core/src/source/page-tree/builder.ts (tree). In this repo fumadocs-ui is aliased to @fumadocs/base-ui (packages/base-ui in the checkout); the layout API is identical.
Slugs
dir/page.mdx→/docs/dir/page;dir/index.mdx→/docs/dir.- A parenthesized folder
(name)/is slug-transparent: stripped from slugs, so children keep parent-level URLs. Use it for sidebar-only grouping. - Each URL may appear once in the entire tree — duplicates are an error by design.
meta.json
Folder fields: title, icon, description, defaultOpen, collapsible, root, pages, pagesIndex.
pages entry syntax:
| Entry | Meaning |
|---|---|
"page" / "dir" |
path to a page or folder (relative paths allowed) |
"(group)" |
folder group, referenced by its literal name |
"---Label---" |
separator (icon form: ---[Icon]Label---) |
"[Text](url)" |
link; external:[Text](url) marks it external |
"..." / "z...a" |
remaining items, alphabetical / reversed |
"...dir" |
inline a folder's items into this level |
"!item" |
exclude from ... |
pagesis exhaustive: once present, unlisted items are dropped unless...appears. Use an explicit array to pin sidebar order."root": truemakes a root folder: rendered as layout tabs, and only the active root's items are visible.
Clickable section header (folder index)
A folder containing an index page attaches it as the folder's own link: the header becomes clickable and the index leaves the child list.
- Keep
pagesfree of"index"— the index auto-resolves. Listing it demotes the folder to a plain label with the index as an ordinary child row (builder.tsdeletesnode.indexwhenpagesclaims it). pagesIndexoverrides which page (or[Text](url)link) serves as the folder's index.- Slug-transparent group + index composes into "section header linking to a parent-level URL":
(intro)/index.mdxgives a clickable Intro header →/docs, with siblings like(intro)/install.mdx→/docs/install.
Sidebar expansion
<DocsLayout sidebar={{ defaultOpenLevel: n }}>— a folder starts open whendefaultOpenLevel >= depth(top-level folders are depth 1) or when it contains the active page. Default0: everything starts collapsed.- Per-folder overrides in its
meta.json:defaultOpen: trueopens one folder;collapsible: falsepins it open with no toggle.