> For AI agents: the complete documentation index is available at https://rspress.rs/llms.txt, the full documentation bundle is available at https://rspress.rs/llms-full.txt.

# Autogenerated navigation

In Rspress, you can either declare [nav](https://rspress.rs/api/config/config-theme.md#nav) and [sidebar](https://rspress.rs/api/config/config-theme.md#sidebar) in the config file or generate them automatically from `_nav.json` and `_meta.json`. We recommend the latter because it keeps the config file concise, supports HMR, and still exposes everything under `themeConfig`.

:::tip
Autogenerated navbar/sidebar only works when `rspress.config.ts` does not define `nav` or `sidebar`.
:::

## Basic usage

Rspress generates the navbar from `_nav.json` and the sidebar from `_meta.json`. The navbar-level `_nav.json` lives in the docs root, while sidebar-level `_meta.json` files live in subdirectories under the docs root. For example:

```tree
docs
├── _nav.json // navigation bar level
└── guide
    ├── _meta.json // sidebar level
    ├── introduction.mdx
    └── advanced
        ├── _meta.json // sidebar level
        └── plugin-development.md
```

If your site uses i18n, place the navbar-level `_nav.json` in each language directory:

```tree
docs
├── en
│   ├── _nav.json // navigation bar level
│   └── guide
│       ├── _meta.json // sidebar level
│       ├── introduction.mdx
│       ├── install.mdx
│       └── advanced
│           ├── _meta.json // sidebar level
│           └── plugin-development.md
└── zh
    ├── _nav.json // navigation bar level
    └── guide
        ├── _meta.json // sidebar level
        ├── introduction.mdx
        ├── install.mdx
        └── advanced
            ├── _meta.json // sidebar level
            └── plugin-development.md
```

## Global sidebar usage

By default (only `_nav.json` exists at the root), Rspress generates a **separate sidebar for each subdirectory**. The sidebar switches automatically based on the currently active nav item. For example, clicking the "Guide" nav item shows the Guide sidebar, and clicking "API" shows the API sidebar:

```tree
docs
├── _nav.json
├── guide
│   ├── _meta.json  // sidebar for /guide
│   └── ...
└── api
    ├── _meta.json  // sidebar for /api
    └── ...
```

If you want all pages to **share a single global sidebar** instead of switching by nav, you can add a `_meta.json` at the root level of the docs directory (alongside `_nav.json`).

This approach works better for documentation sites with **fewer nav items and a simpler structure**. Since the sidebar stays the same regardless of which nav item is active, it is a good fit when you want to organize the whole site under one unified sidebar:

```tree
docs
├── _nav.json
├── _meta.json  // root-level _meta.json → global sidebar
├── guide
│   ├── _meta.json
│   └── ...
└── api
    ├── _meta.json
    └── ...
```

When a root-level `_meta.json` exists, Rspress will generate a single sidebar (keyed by `'/'`) for all pages, regardless of which nav item is active. The root `_meta.json` serves as the entry point for the entire sidebar tree, and you can typically organize subdirectories with section headers:

```json title="docs/_meta.json"
[
  {
    "type": "dir-section-header",
    "name": "guide",
    "label": "Guide"
  },
  {
    "type": "dir-section-header",
    "name": "api",
    "label": "API"
  }
]
```

## JSON schema type hint

To improve editing for `_nav.json` and `_meta.json`, Rspress provides two schema files for IDE hints: `@rspress/core/meta-json-schema.json` and `@rspress/core/nav-json-schema.json`.

For example, in VSCode, you can add the following configuration in `.vscode/settings.json`:

```json title=".vscode/settings.json"
{
  //...
  "json.schemas": [
    {
      "fileMatch": ["**/_meta.json"],
      "url": "./node_modules/@rspress/core/meta-json-schema.json"
      // or "url": "https://unpkg.com/@rspress/core@2.0.0/meta-json-schema.json"
    },
    {
      "fileMatch": ["**/_nav.json"],
      "url": "./node_modules/@rspress/core/nav-json-schema.json"
      // or "url": "https://unpkg.com/@rspress/core@2.0.0/nav-json-schema.json"
    }
  ]
  // ...
}
```

## Navbar level config

At the navbar level, `_nav.json` accepts an array with the same type as the default theme's nav config. For details, see [nav config](https://rspress.rs/api/config/config-theme.md#nav). For example:

```json title="docs/_nav.json"
[
  {
    "text": "Guide",
    "link": "/guide/introduction",
    "activeMatch": "^/guide/"
  }
]
```

## Sidebar level config

At the sidebar level, `_meta.json` accepts an array whose items use the following types:

```ts
export type FileSideMeta = {
  type: 'file';
  name: string;
  label?: string;
  icon?: string;
  tag?: string;
  overviewHeaders?: number[];
  context?: string;
};

export type DirSideMeta = {
  type: 'dir';
  name: string;
  label?: string;
  collapsible?: boolean;
  collapsed?: boolean;
  icon?: string;
  tag?: string;
  overviewHeaders?: number[];
  context?: string;
};

export type DirSectionHeaderSideMeta = Omit<DirSideMeta, 'type'> &
  Omit<SectionHeaderMeta, 'type'> & { type: 'dir-section-header' };

export type DividerSideMeta = {
  type: 'divider';
  dashed?: boolean;
};

export type SectionHeaderMeta = {
  type: 'section-header';
  label: string;
  icon?: string;
  tag?: string;
};

export type CustomLinkMeta =
  | {
      // file link
      type: 'custom-link';
      label: string;
      icon?: string;
      tag?: string;
      overviewHeaders?: number[];
      context?: string;
      link: string;
    }
  | {
      // dir link
      type: 'custom-link';
      label: string;
      icon?: string;
      tag?: string;
      overviewHeaders?: number[];
      context?: string;
      link?: string;
      collapsible?: boolean;
      collapsed?: boolean;
      items: _CustomLinkMetaWithoutTypeField[];
    };

export type SideMetaItem =
  | FileSideMeta
  | DirSideMeta
  | DirSectionHeaderSideMeta
  | DividerSideMeta
  | SectionHeaderMeta
  | CustomLinkMeta
  | string;
```

### file

- When the item is a `string`, it represents a file. The string is the file name:

```json
["introduction"]
```

The file name may include a suffix or omit it. For example, `introduction` is resolved as `introduction.mdx`.

- When the item is an object, it can describe a file, directory, or custom link.

To describe a **file**, use the following type:

```ts
export type FileSideMeta = {
  type: 'file';
  name: string;
  label?: string;
  icon?: string;
  tag?: string;
  overviewHeaders?: number[];
  context?: string;
};
```

Here, `name` is the file name with or without a suffix, and `label` is the file's display name in the sidebar. If `label` is omitted, Rspress uses the document's H1 title automatically. `overviewHeaders` controls which headings are shown on the file's overview page; it is optional and defaults to `[2]`. `context` adds a `data-context` attribute to the generated sidebar DOM node; it is optional and omitted by default. For example:

```json
{
  "type": "file",
  "name": "introduction",
  "label": "Introduction"
}
```

### dir

To describe a **directory**, use the following type:

```ts
export type DirSideMeta = {
  type: 'dir';
  name: string;
  label?: string;
  collapsible?: boolean;
  collapsed?: boolean;
  icon?: string;
  tag?: string;
  overviewHeaders?: number[];
  context?: string;
};
```

Here, `name` is the directory name, `label` is the directory's display name in the sidebar, `collapsible` controls whether the directory can be collapsed, and `collapsed` controls whether it is collapsed by default. `overviewHeaders` controls which headings are shown on overview pages for files in this directory; it is optional and defaults to `[2]`. `context` adds a `data-context` attribute to the generated sidebar DOM node; it is optional and omitted by default. For example:

```json
{
  "type": "dir",
  "name": "advanced",
  "label": "Advanced",
  "collapsible": true,
  "collapsed": false
}
```

:::tip

To display a document when users click a sidebar directory, create an `index.mdx` file inside that directory. For example:

```tree
docs
└── basic
    ├── guide
    │   ├── index.mdx
    │   ├── getting-started.mdx
    │   └── _meta.json
    └── _meta.json
```

```json title="basic/_meta.json"
[{ "type": "dir", "name": "guide" }]
```

```json title="basic/guide/_meta.json"
["getting-started"]
```

This sidebar contains only the `getting-started` document. When users click the `Guide` directory, Rspress displays the content of `index.mdx`.

:::

### dir-section-header new
When describing a **directory**, you can also use `dir-section-header`. It behaves like `"type": "dir"` but renders differently in the UI. It is often used at the first level, where the directory title appears as a [section header](#section-header) at the same level as files inside the directory.

Type:

```ts
export type DirSectionHeaderSideMeta = Omit<DirSideMeta, 'type'> &
  Omit<SectionHeaderMeta, 'type'> & { type: 'dir-section-header' };
```

```json
{
  "type": "dir-section-header",
  "name": "advanced",
  "label": "Advanced",
  "collapsible": true,
  "collapsed": false
}
```

### divider

To describe a **divider**, use the following type:

```ts
export type DividerSideMeta = {
  type: 'divider';
  dashed?: boolean;
};
```

When `dashed` is `true`, the divider is dashed. Otherwise, it is solid.

### section-header

To describe a **section header**, use the following type:

```ts
export type SectionHeaderMeta = {
  type: 'section-header';
  label: string;
  icon?: string;
  tag?: string;
};
```

Here, `label` is the section header's display name in the sidebar. For example:

```json
{
  "type": "section-header",
  "label": "Section Header"
}
```

Section headers make it easier to group documents and directories in the sidebar. You can combine them with `divider` to separate groups more clearly:

```json
[
  {
    "type": "section-header",
    "label": "Section 1"
  },
  "introduction",
  {
    "type": "divider"
  },
  {
    "type": "section-header",
    "label": "Section 2"
  },
  "advanced"
]
```

### custom-link

To describe a **custom link**, use the following type:

```ts
export type CustomLinkMeta =
  | {
      // file link
      type: 'custom-link';
      label: string;
      icon?: string;
      tag?: string;
      overviewHeaders?: number[];
      context?: string;
      link: string;
    }
  | {
      // dir link
      type: 'custom-link';
      label: string;
      icon?: string;
      tag?: string;
      overviewHeaders?: number[];
      context?: string;
      link?: string;
      collapsible?: boolean;
      collapsed?: boolean;
      items: _CustomLinkMetaWithoutTypeField[];
    };
```

Here, `link` is the link target and `label` is the display name in the sidebar. For example:

```json
{
  "type": "custom-link",
  "link": "/my-link",
  "label": "My Link"
}
```

`link` supports external links, for example:

```json
{
  "type": "custom-link",
  "link": "https://github.com",
  "label": "GitHub"
}
```

You can also use `items` to create nested custom links, for example:

```json
{
  "type": "custom-link",
  "label": "My Link",
  "items": [
    {
      "type": "custom-link",
      "label": "Sub Link 1",
      "link": "/sub-link-1"
    },
    {
      "type": "custom-link",
      "label": "Sub Link 2",
      "link": "/sub-link-2"
    }
  ]
}
```

### Complete example

Here is a complete example using the three types above:

```json
[
  "install",
  {
    "type": "file",
    "name": "introduction",
    "label": "Introduction"
  },
  {
    "type": "dir",
    "name": "advanced",
    "label": "Advanced",
    "collapsible": true,
    "collapsed": false
  },
  {
    "type": "custom-link",
    "link": "/my-link",
    "label": "My Link"
  }
]
```

### No config usage

In some directories, you can omit `_meta.json` and let Rspress generate the sidebar automatically. This works when the directory contains only documents, no subdirectories, and you do not need a custom document order. For example:

```tree
docs
├── _meta.json
└── guide
  ├── _meta.json
  └── basic
    ├── introduction.mdx
    ├── install.mdx
    └── plugin-development.md
```

In the `guide` directory, configure `_meta.json` as follows:

```json
[
  {
    "type": "dir",
    "name": "basic",
    "label": "Basic",
    "collapsible": true,
    "collapsed": false
  }
]
```

In the `basic` directory, you can omit `_meta.json`; Rspress then generates the sidebar automatically and sorts files alphabetically by file name. To customize the order, prefix file names with numbers:

```tree
basic
  ├── 1-introduction.mdx
  ├── 2-install.mdx
  └── 3-plugin-development.md
```

## Configure file items with frontmatter

Most display fields for automatically generated file items can be declared in the page frontmatter: `title`, `icon`, `tag`, `overviewHeaders`, and `context`.

Keep structural settings in `_meta.json`, including item order, `type`, `name`, directory groups, section headers, custom links, `collapsible`, and `collapsed`. For page-specific metadata, prefer frontmatter so the content and its sidebar presentation stay together.

For example, `_meta.json` can define which files appear and in what order:

```json title="docs/guide/_meta.json"
["introduction"]
```

Then configure the file item's display metadata in the page frontmatter:

```md title="docs/guide/introduction.mdx"
---
title: Introduction
icon: /icon.png
tag: new
overviewHeaders: [2, 3]
context: guide-introduction
---

# Introduction
```

When a file item defines the same field in both places, frontmatter takes precedence for `icon`, `tag`, `overviewHeaders`, and `context`, while `label` in `_meta.json` takes precedence over the page title. For a directory group, `_meta.json` takes precedence over metadata from its index page.

## Sidebar icons and tags

Use `icon` to add an icon before a sidebar title. The recommended and most common approach is to place the image in the `public` directory and reference it with an absolute path.

For example, place a local image at `docs/public/icon.png`, then reference it in `_meta.json`:

```json title="docs/_meta.json"
[
  {
    "type": "file",
    "name": "introduction",
    "label": "Introduction",
    "icon": "/icon.png",
    "tag": "new"
  }
]
```

You can also provide an inline SVG string when you want to embed the icon directly in the configuration:

```json title="docs/_meta.json"
[
  {
    "type": "file",
    "name": "introduction",
    "icon": "<svg width=\"1em\" height=\"1em\" viewBox=\"0 0 32 32\"><path fill=\"currentColor\" d=\"M4 6h24v2H4zm0 18h24v2H4zm0-12h24v2H4zm0 6h24v2H4z\"/></svg>"
  }
]
```

Emoji, external URLs, and data URLs are also supported. The existing `tag` config remains after the title.

For details about `tag`, see [Tag Component](https://rspress.rs/ui/layout-components/tag.md).
