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, and this page is available as Markdown at https://rspress.rs/api/config/config-basic.md.
close
  • English
  • Basic config

    root

    • Type: string
    • Default: docs

    Specifies the docs root directory. For example:

    rspress.config.ts
    import { 
    function defineConfig<const Config extends UserConfig>(config: () => Promise<Config>): UserConfigAsyncFn (+1 overload)

    Define an async Rspress configuration function. Use this overload when you need to perform async operations during configuration, such as fetching remote data, reading files, or dynamically generating config.

    @paramconfig - An async function that returns the Rspress configuration.@returnsThe same async function (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig(async () => {
      const remoteConfig = await fetchConfig();
      return {
        title: remoteConfig.title,
      };
    });
    defineConfig
    } from '@rspress/core';
    export default
    function defineConfig(config: UserConfig): UserConfig (+1 overload)

    Define a static Rspress configuration object.

    @paramconfig - The Rspress configuration object.@returnsThe same configuration object (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      title: 'My Site',
    });
    defineConfig
    ({
    UserConfig.root?: string | undefined

    The root directory of the site.

    @default'docs'
    root
    : 'docs',
    });

    This option supports both relative and absolute paths. Relative paths are resolved from the current working directory (cwd).

    You can also pass the docs root as a CLI argument:

    rspress dev docs
    rspress build docs

    base

    • Type: string
    • Default: /

    Deployment base path. For example, if you plan to deploy your site to https://foo.github.io/bar/, then you should set base to "/bar/":

    rspress.config.ts
    import { 
    function defineConfig<const Config extends UserConfig>(config: () => Promise<Config>): UserConfigAsyncFn (+1 overload)

    Define an async Rspress configuration function. Use this overload when you need to perform async operations during configuration, such as fetching remote data, reading files, or dynamically generating config.

    @paramconfig - An async function that returns the Rspress configuration.@returnsThe same async function (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig(async () => {
      const remoteConfig = await fetchConfig();
      return {
        title: remoteConfig.title,
      };
    });
    defineConfig
    } from '@rspress/core';
    export default
    function defineConfig(config: UserConfig): UserConfig (+1 overload)

    Define a static Rspress configuration object.

    @paramconfig - The Rspress configuration object.@returnsThe same configuration object (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      title: 'My Site',
    });
    defineConfig
    ({
    UserConfig.base?: string | undefined

    Base path of the site.

    @default'/'
    base
    : '/bar/',
    });

    siteOrigin

    • Type: string
    • Default: ""

    The optional deployment origin of the site, for example https://foo.github.io.

    Rspress uses this value together with base when generated files need absolute URLs, such as sitemap.xml, llms.txt links, or plugin outputs. The full URL concatenation order is siteOrigin + base + routePath.

    If siteOrigin is not configured, Rspress uses base + routePath as the fallback.

    If your site is deployed to https://foo.github.io/bar/, set siteOrigin to "https://foo.github.io" and base to "/bar/":

    rspress.config.ts
    import { 
    function defineConfig<const Config extends UserConfig>(config: () => Promise<Config>): UserConfigAsyncFn (+1 overload)

    Define an async Rspress configuration function. Use this overload when you need to perform async operations during configuration, such as fetching remote data, reading files, or dynamically generating config.

    @paramconfig - An async function that returns the Rspress configuration.@returnsThe same async function (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig(async () => {
      const remoteConfig = await fetchConfig();
      return {
        title: remoteConfig.title,
      };
    });
    defineConfig
    } from '@rspress/core';
    export default
    function defineConfig(config: UserConfig): UserConfig (+1 overload)

    Define a static Rspress configuration object.

    @paramconfig - The Rspress configuration object.@returnsThe same configuration object (enables type checking and IDE autocompletion).@example
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      title: 'My Site',
    });
    defineConfig
    ({
    UserConfig.siteOrigin?: string | undefined

    Origin of the site, such as https://example.com.

    siteOrigin
    : 'https://foo.github.io',
    UserConfig.base?: string | undefined

    Base path of the site.

    @default'/'
    base
    : '/bar/',
    });

    title

    • Type: string
    • Default: "Rspress"

    Site title. Rspress uses this as the HTML page title. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      title: 'My Site',
    });

    description

    • Type: string
    • Default: ""

    Site description. Rspress uses this as the HTML page description. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      description: 'My Site Description',
    });

    icon

    • Type: string | URL
    • Default: ""

    Site icon. Rspress uses this path as the page icon. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      icon: '/favicon.ico',
    });

    For a normal path, Rspress resolves the icon from the public directory. You can also use a CDN URL, the file:// protocol, or a URL object for a local absolute path.

    lang

    • Type: string
    • Default: "en"

    Default language of the site. See i18n for more details.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      lang: 'en',
      locales: [
        {
          lang: 'en',
          // ...
        },
        {
          lang: 'zh',
          // ...
        },
      ],
    });

    locales

    • Type: Locale[]
    • Default: undefined

    Configures the supported languages and site information for each language.

    export interface Locale {
      lang: string;
      label: string;
      title?: string;
      description?: string;
    }
    FieldDescription
    langLanguage code. Must match the corresponding directory name under the docs root.
    labelDisplay text in the navbar language switcher.
    titleSite title for this language.
    descriptionSite description for this language.

    Set the top-level lang to one of these language codes to select the default language. Rspress omits the language prefix from the default language's routes.

    For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      lang: 'en',
      locales: [
        {
          lang: 'en',
          label: 'English',
          title: 'My Site',
          description: 'My site description',
        },
        {
          lang: 'zh',
          label: '简体中文',
          title: '站点标题',
          description: '站点描述',
        },
      ],
    });

    For the complete setup, see i18n. For language-specific theme options such as nav and sidebar, see themeConfig.locales.

    i18nSourcePath

    • Type: string
    • Default: path.join(cwd, 'i18n.json')

    Specifies the path of the i18n text data source file. By default, Rspress reads from i18n.json in the current working directory. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import path from 'path';
    
    export default defineConfig({
      i18nSourcePath: path.join(__dirname, 'config/i18n.json'),
    });
    Tip

    This has the same effect as placing an i18n.json at the project root. If you also configure i18nSource, the i18nSource will be merged with and take priority over the data loaded from i18nSourcePath.

    i18nSource

    • Type: Record<string, Record<string, string>> | ((value: Record<string, Record<string, string>>) => Record<string, Record<string, string>> | Promise<Record<string, Record<string, string>>>)
    • Default: {}

    Use this option to modify Rspress's built-in i18n text or add text for custom components. It is usually used together with useI18n.

    Tip

    This has the same implementation and effect as i18n.json. You can use either one. i18nSource has higher priority than i18n.json and supports functions.

    The i18nSource parameter is an object with the following structure:

    {
      [textKey: string]: {
        [locale: string]: string;
      }
    }

    The first-level textKey is the text key, the second-level locale is the language code (for example, zh or en), and the value is the translated text for that language.

    Here is an example of modifying Rspress's built-in i18n text:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    export default defineConfig({
      i18nSource: {
        editLinkText: {
          en: '📝 Edit this page on Gitlab',
          zh: '📝 在 Gitlab 上编辑此页',
        },
      },
    });

    i18nSource can also be a function, for example:

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      i18nSource: async source => {
        for (const key of Object.keys(source)) {
          source[key]['en_US'] = source[key]['en'];
        }
        return source;
      },
    });

    Here are the built-in i18n texts in Rspress:

    import type { I18nText } from '@rspress/core';
    
    // cspell:disable
    export const DEFAULT_I18N_TEXT = {
      languagesText: {
        zh: '语言',
        en: 'Languages',
        ja: '言語',
        ko: '언어',
        ru: 'Языки',
        ta: 'மொழிகள்',
        es: 'Idiomas',
        fr: 'Langues',
        de: 'Sprachen',
        pt: 'Idiomas',
        'pt-BR': 'Idiomas',
        'zh-Hant': '語言',
        'zh-TW': '語言',
        it: 'Lingue',
        pl: 'Języki',
        vi: 'Ngôn ngữ',
        tr: 'Diller',
        cs: 'Jazyky',
        nl: 'Talen',
      },
      themeText: {
        zh: '主题',
        en: 'Theme',
        ja: 'テーマ',
        ko: '테마',
        ru: 'Тема',
        ta: 'தோற்றம்',
        es: 'Tema',
        fr: 'Thème',
        de: 'Design',
        pt: 'Tema',
        'pt-BR': 'Tema',
        'zh-Hant': '主題',
        'zh-TW': '主題',
        it: 'Tema',
        pl: 'Motyw',
        vi: 'Giao diện',
        tr: 'Tema',
        cs: 'Motiv',
        nl: 'Thema',
      },
      versionsText: {
        zh: '版本',
        en: 'Versions',
        ja: 'バージョン',
        ko: '버전',
        ru: 'Версии',
        ta: 'பதிப்புகள்',
        es: 'Versiones',
        fr: 'Versions',
        de: 'Versionen',
        pt: 'Versões',
        'pt-BR': 'Versões',
        'zh-Hant': '版本',
        'zh-TW': '版本',
        it: 'Versioni',
        pl: 'Wersje',
        vi: 'Phiên bản',
        tr: 'Sürümler',
        cs: 'Verze',
        nl: 'Versies',
      },
      menuTitle: {
        zh: '菜单',
        en: 'Menu',
        ja: 'メニュー',
        ko: '사이드바 메뉴',
        ru: 'Меню',
        ta: 'பட்டி',
        es: 'Menú',
        fr: 'Menu',
        de: 'Menü',
        pt: 'Menu',
        'pt-BR': 'Menu',
        'zh-Hant': '選單',
        'zh-TW': '選單',
        it: 'Menu',
        pl: 'Menu',
        vi: 'Trình đơn',
        tr: 'Menü',
        cs: 'Nabídka',
        nl: 'Menu',
      },
      outlineTitle: {
        zh: '目录',
        en: 'ON THIS PAGE',
        ja: '目次',
        ko: '이 페이지 목차',
        ru: 'ОГЛАВЛЕНИЕ',
        ta: 'இந்தப் பக்கத்தில்',
        es: 'EN ESTA PÁGINA',
        fr: 'SUR CETTE PAGE',
        de: 'AUF DIESER SEITE',
        pt: 'NESTA PÁGINA',
        'pt-BR': 'NESTA PÁGINA',
        'zh-Hant': '本頁目錄',
        'zh-TW': '本頁目錄',
        it: 'IN QUESTA PAGINA',
        pl: 'NA TEJ STRONIE',
        vi: 'TRÊN TRANG NÀY',
        tr: 'BU SAYFADA',
        cs: 'NA TÉTO STRÁNCE',
        nl: 'OP DEZE PAGINA',
      },
      scrollToTopText: {
        en: 'Back to top',
        zh: '回到顶部',
        ja: 'トップに戻る',
        ko: '맨 위로',
        ru: 'Наверх',
        ta: 'பக்கத்தின் மேலே செல்லவும்',
        es: 'Volver arriba',
        fr: 'Retour en haut',
        de: 'Nach oben',
        pt: 'Voltar ao topo',
        'pt-BR': 'Voltar ao topo',
        'zh-Hant': '回到頂端',
        'zh-TW': '回到頂端',
        it: 'Torna in alto',
        pl: 'Wróć na górę',
        vi: 'Về đầu trang',
        tr: 'Başa dön',
        cs: 'Zpět nahoru',
        nl: 'Terug naar boven',
      },
      lastUpdatedText: {
        en: 'Last Updated',
        zh: '最后更新于',
        ja: '最終更新',
        ko: '업데이트 날짜',
        ru: 'Последнее обновление',
        ta: 'கடைசியாகப் புதுப்பிக்கப்பட்டது',
        es: 'Última actualización',
        fr: 'Dernière mise à jour',
        de: 'Zuletzt aktualisiert',
        pt: 'Última atualização',
        'pt-BR': 'Última atualização',
        'zh-Hant': '最後更新於',
        'zh-TW': '最後更新於',
        it: 'Ultimo aggiornamento',
        pl: 'Ostatnia aktualizacja',
        vi: 'Cập nhật lần cuối',
        tr: 'Son güncelleme',
        cs: 'Naposledy aktualizováno',
        nl: 'Laatst bijgewerkt',
      },
      lastUpdatedAuthorText: {
        en: 'by',
        zh: '作者',
        ja: '更新者',
        ko: '작성자',
        ru: 'автор',
        ta: 'புதுப்பித்தவர்',
        es: 'por',
        fr: 'par',
        de: 'von',
        pt: 'por',
        'pt-BR': 'por',
        'zh-Hant': '作者',
        'zh-TW': '作者',
        it: 'di',
        pl: 'przez',
        vi: 'bởi',
        tr: 'Güncelleyen',
        cs: 'Autor aktualizace',
        nl: 'door',
      },
      prevPageText: {
        en: 'Previous page',
        zh: '上一页',
        ja: '前のページ',
        ko: '이전 페이지',
        ru: 'Предыдущая страница',
        ta: 'முந்தைய பக்கம்',
        es: 'Página anterior',
        fr: 'Page précédente',
        de: 'Vorherige Seite',
        pt: 'Página anterior',
        'pt-BR': 'Página anterior',
        'zh-Hant': '上一頁',
        'zh-TW': '上一頁',
        it: 'Pagina precedente',
        pl: 'Poprzednia strona',
        vi: 'Trang trước',
        tr: 'Önceki sayfa',
        cs: 'Předchozí stránka',
        nl: 'Vorige pagina',
      },
      nextPageText: {
        en: 'Next page',
        zh: '下一页',
        ja: '次のページ',
        ko: '다음 페이지',
        ru: 'Следующая страница',
        ta: 'அடுத்த பக்கம்',
        es: 'Página siguiente',
        fr: 'Page suivante',
        de: 'Nächste Seite',
        pt: 'Página seguinte',
        'pt-BR': 'Próxima página',
        'zh-Hant': '下一頁',
        'zh-TW': '下一頁',
        it: 'Pagina successiva',
        pl: 'Następna strona',
        vi: 'Trang sau',
        tr: 'Sonraki sayfa',
        cs: 'Další stránka',
        nl: 'Volgende pagina',
      },
      sourceCodeText: {
        en: 'Source Code',
        zh: '源码',
        ja: 'ソースコード',
        ko: '소스 코드',
        ru: 'Исходный код',
        ta: 'மூலக் குறியீடு',
        es: 'Código fuente',
        fr: 'Code source',
        de: 'Quellcode',
        pt: 'Código-fonte',
        'pt-BR': 'Código-fonte',
        'zh-Hant': '原始碼',
        'zh-TW': '原始碼',
        it: 'Codice sorgente',
        pl: 'Kod źródłowy',
        vi: 'Mã nguồn',
        tr: 'Kaynak kodu',
        cs: 'Zdrojový kód',
        nl: 'Broncode',
      },
      searchPlaceholderText: {
        en: 'Search',
        zh: '搜索',
        ja: '検索',
        ko: '검색',
        ru: 'Поиск',
        ta: 'தேடுக',
        es: 'Buscar',
        fr: 'Rechercher',
        de: 'Suchen',
        pt: 'Pesquisar',
        'pt-BR': 'Buscar',
        'zh-Hant': '搜尋',
        'zh-TW': '搜尋',
        it: 'Cerca',
        pl: 'Szukaj',
        vi: 'Tìm kiếm',
        tr: 'Ara',
        cs: 'Hledat',
        nl: 'Zoeken',
      },
      searchPanelCancelText: {
        en: 'Cancel',
        zh: '取消',
        ja: 'キャンセル',
        ko: '취소',
        ru: 'Отмена',
        ta: 'ரத்து செய்',
        es: 'Cancelar',
        fr: 'Annuler',
        de: 'Abbrechen',
        pt: 'Cancelar',
        'pt-BR': 'Cancelar',
        'zh-Hant': '取消',
        'zh-TW': '取消',
        it: 'Annulla',
        pl: 'Anuluj',
        vi: 'Hủy',
        tr: 'İptal',
        cs: 'Zrušit',
        nl: 'Annuleren',
      },
      searchNoResultsText: {
        en: 'No matching results',
        zh: '未找到与之匹配的结果',
        ja: '一致する結果が見つかりません',
        ko: '일치하는 결과가 없습니다',
        ru: 'Нет результатов, соответствующих запросу',
        ta: 'பொருந்தும் முடிவுகள் இல்லை',
        es: 'No se encontraron resultados',
        fr: 'Aucun résultat correspondant',
        de: 'Keine passenden Ergebnisse',
        pt: 'Nenhum resultado correspondente',
        'pt-BR': 'Nenhum resultado encontrado',
        'zh-Hant': '找不到符合的結果',
        'zh-TW': '找不到符合的結果',
        it: 'Nessun risultato corrispondente',
        pl: 'Brak pasujących wyników',
        vi: 'Không tìm thấy kết quả phù hợp',
        tr: 'Eşleşen sonuç bulunamadı',
        cs: 'Nebyly nalezeny žádné odpovídající výsledky',
        nl: 'Geen overeenkomende resultaten',
      },
      searchSuggestedQueryText: {
        en: 'Try searching for different keywords',
        zh: '试试搜索不同关键词',
        ja: '別のキーワードで検索してみてください',
        ko: '다른 키워드로 검색해 보세요',
        ru: 'Попробуйте поискать по другим ключевым словам',
        ta: 'வேறு தேடல் சொற்களை முயற்சிக்கவும்',
        es: 'Prueba con otras palabras clave',
        fr: 'Essayez d’autres mots-clés',
        de: 'Versuche es mit anderen Suchbegriffen',
        pt: 'Experimente pesquisar com outras palavras-chave',
        'pt-BR': 'Tente buscar com outras palavras-chave',
        'zh-Hant': '試著搜尋其他關鍵字',
        'zh-TW': '試著搜尋其他關鍵字',
        it: 'Prova a cercare con altre parole chiave',
        pl: 'Spróbuj wyszukać inne słowa kluczowe',
        vi: 'Thử tìm kiếm bằng từ khóa khác',
        tr: 'Farklı anahtar kelimelerle aramayı dene',
        cs: 'Zkuste vyhledat jiná klíčová slova',
        nl: 'Probeer andere zoektermen',
      },
      'overview.filterNameText': {
        en: 'Filter',
        zh: '筛选',
        ja: 'フィルター',
        ko: '필터',
        ru: 'Фильтр',
        ta: 'வடிகட்டு',
        es: 'Filtrar',
        fr: 'Filtrer',
        de: 'Filtern',
        pt: 'Filtrar',
        'pt-BR': 'Filtrar',
        'zh-Hant': '篩選',
        'zh-TW': '篩選',
        it: 'Filtra',
        pl: 'Filtruj',
        vi: 'Lọc',
        tr: 'Filtrele',
        cs: 'Filtrovat',
        nl: 'Filteren',
      },
      'overview.filterPlaceholderText': {
        en: 'Search API',
        zh: '搜索 API',
        ja: 'API を検索',
        ko: 'API 검색',
        ru: 'API поиска',
        ta: 'API-ஐத் தேடுக',
        es: 'Buscar en la API',
        fr: 'Rechercher une API',
        de: 'API suchen',
        pt: 'Pesquisar API',
        'pt-BR': 'Buscar API',
        'zh-Hant': '搜尋 API',
        'zh-TW': '搜尋 API',
        it: 'Cerca API',
        pl: 'Szukaj API',
        vi: 'Tìm API',
        tr: 'API ara',
        cs: 'Hledat API',
        nl: 'API zoeken',
      },
      'overview.filterNoResultText': {
        en: 'No matching API found',
        zh: '未找到匹配的 API',
        ja: '一致する API が見つかりません',
        ko: '일치하는 API가 없습니다',
        ru: 'Не найден подходящий API',
        ta: 'பொருந்தும் API எதுவும் கிடைக்கவில்லை',
        es: 'No se encontró ninguna API',
        fr: 'Aucune API correspondante',
        de: 'Keine passende API gefunden',
        pt: 'Não foi encontrada nenhuma API correspondente',
        'pt-BR': 'Nenhuma API correspondente encontrada',
        'zh-Hant': '找不到符合的 API',
        'zh-TW': '找不到符合的 API',
        it: 'Nessuna API corrispondente',
        pl: 'Nie znaleziono pasującego API',
        vi: 'Không tìm thấy API phù hợp',
        tr: 'Eşleşen API bulunamadı',
        cs: 'Nebylo nalezeno odpovídající API',
        nl: 'Geen overeenkomende API gevonden',
      },
      openInText: {
        en: 'Open in {{name}}',
        zh: '在 {{name}} 中打开',
        ja: '{{name}} で開く',
        ko: '{{name}}에서 열기',
        ru: 'Открыть в {{name}}',
        ta: '{{name}}-இல் திறக்கவும்',
        es: 'Abrir en {{name}}',
        fr: 'Ouvrir dans {{name}}',
        de: 'In {{name}} öffnen',
        pt: 'Abrir em {{name}}',
        'pt-BR': 'Abrir em {{name}}',
        'zh-Hant': '在 {{name}} 中開啟',
        'zh-TW': '在 {{name}} 中開啟',
        it: 'Apri in {{name}}',
        pl: 'Otwórz w {{name}}',
        vi: 'Mở trong {{name}}',
        tr: '{{name}} ile aç',
        cs: 'Otevřít v aplikaci {{name}}',
        nl: 'Openen in {{name}}',
      },
      copyMarkdownText: {
        en: 'Copy Markdown',
        zh: '复制 Markdown',
        ja: 'Markdown をコピー',
        ko: '마크다운 복사',
        ru: 'Скопировать Markdown',
        ta: 'Markdown-ஐ நகலெடு',
        es: 'Copiar Markdown',
        fr: 'Copier le Markdown',
        de: 'Markdown kopieren',
        pt: 'Copiar Markdown',
        'pt-BR': 'Copiar Markdown',
        'zh-Hant': '複製 Markdown',
        'zh-TW': '複製 Markdown',
        it: 'Copia Markdown',
        pl: 'Skopiuj Markdown',
        vi: 'Sao chép Markdown',
        tr: 'Markdown’u kopyala',
        cs: 'Zkopírovat Markdown',
        nl: 'Markdown kopiëren',
      },
      copyMarkdownLinkText: {
        en: 'Copy Markdown link',
        zh: '复制 Markdown 链接',
        ja: 'Markdown リンクをコピー',
        ko: '마크다운 링크 복사',
        ru: 'Скопировать ссылку в формате Markdown',
        ta: 'Markdown இணைப்பை நகலெடு',
        es: 'Copiar enlace de Markdown',
        fr: 'Copier le lien Markdown',
        de: 'Markdown-Link kopieren',
        pt: 'Copiar ligação Markdown',
        'pt-BR': 'Copiar link do Markdown',
        'zh-Hant': '複製 Markdown 連結',
        'zh-TW': '複製 Markdown 連結',
        it: 'Copia il link Markdown',
        pl: 'Skopiuj link do pliku Markdown',
        vi: 'Sao chép liên kết Markdown',
        tr: 'Markdown bağlantısını kopyala',
        cs: 'Zkopírovat odkaz na Markdown',
        nl: 'Markdown-link kopiëren',
      },
      viewMarkdownText: {
        en: 'View as Markdown',
        zh: '以 Markdown 查看',
        ja: 'Markdown として表示',
        ko: '마크다운으로 보기',
        ru: 'Просмотреть в формате Markdown',
        ta: 'Markdown ஆகப் பார்க்கவும்',
        es: 'Ver como Markdown',
        fr: 'Afficher en Markdown',
        de: 'Als Markdown anzeigen',
        pt: 'Ver como Markdown',
        'pt-BR': 'Ver como Markdown',
        'zh-Hant': '以 Markdown 檢視',
        'zh-TW': '以 Markdown 檢視',
        it: 'Visualizza come Markdown',
        pl: 'Wyświetl jako Markdown',
        vi: 'Xem dưới dạng Markdown',
        tr: 'Markdown olarak görüntüle',
        cs: 'Zobrazit jako Markdown',
        nl: 'Weergeven als Markdown',
      },
      editLinkText: {
        en: 'Edit this page',
        zh: '编辑此页面',
        ja: 'このページを編集',
        ko: '이 페이지 편집',
        ru: 'Отредактировать страницу',
        ta: 'இந்தப் பக்கத்தைத் திருத்தவும்',
        es: 'Editar esta página',
        fr: 'Modifier cette page',
        de: 'Diese Seite bearbeiten',
        pt: 'Editar esta página',
        'pt-BR': 'Editar esta página',
        'zh-Hant': '編輯此頁面',
        'zh-TW': '編輯此頁面',
        it: 'Modifica questa pagina',
        pl: 'Edytuj tę stronę',
        vi: 'Chỉnh sửa trang này',
        tr: 'Bu sayfayı düzenle',
        cs: 'Upravit tuto stránku',
        nl: 'Deze pagina bewerken',
      },
      codeButtonGroupCopyButtonText: {
        en: 'Copy code',
        zh: '复制代码',
        ja: 'コードをコピー',
        ko: '코드 복사',
        ru: 'Скопировать код',
        ta: 'குறியீட்டை நகலெடு',
        es: 'Copiar código',
        fr: 'Copier le code',
        de: 'Code kopieren',
        pt: 'Copiar código',
        'pt-BR': 'Copiar código',
        'zh-Hant': '複製程式碼',
        'zh-TW': '複製程式碼',
        it: 'Copia il codice',
        pl: 'Skopiuj kod',
        vi: 'Sao chép mã',
        tr: 'Kodu kopyala',
        cs: 'Zkopírovat kód',
        nl: 'Code kopiëren',
      },
      codeButtonGroupWrapButtonText: {
        en: 'Toggle code wrap',
        zh: '切换代码换行',
        ja: 'コードの折り返しを切り替え',
        ko: '코드 줄바꿈 전환',
        ru: 'Переключить перенос кода',
        ta: 'குறியீட்டு வரி மடக்கத்தை மாற்று',
        es: 'Activar o desactivar el ajuste de línea',
        fr: 'Activer ou désactiver le retour à la ligne',
        de: 'Zeilenumbruch umschalten',
        pt: 'Alternar a quebra de linha',
        'pt-BR': 'Alternar quebra de linha',
        'zh-Hant': '切換程式碼自動換行',
        'zh-TW': '切換程式碼自動換行',
        it: 'Attiva o disattiva il ritorno a capo',
        pl: 'Przełącz zawijanie wierszy kodu',
        vi: 'Bật hoặc tắt ngắt dòng mã',
        tr: 'Kod satırı kaydırmayı aç veya kapat',
        cs: 'Přepnout zalamování řádků',
        nl: 'Regelterugloop aan- of uitzetten',
      },
      notFoundText: {
        en: 'PAGE NOT FOUND',
        zh: '页面未找到',
        ja: 'ページが見つかりません',
        ko: '페이지를 찾을 수 없음',
        ru: 'СТРАНИЦА НЕ НАЙДЕНА',
        ta: 'பக்கம் கிடைக்கவில்லை',
        es: 'PÁGINA NO ENCONTRADA',
        fr: 'PAGE INTROUVABLE',
        de: 'SEITE NICHT GEFUNDEN',
        pt: 'PÁGINA NÃO ENCONTRADA',
        'pt-BR': 'PÁGINA NÃO ENCONTRADA',
        'zh-Hant': '找不到頁面',
        'zh-TW': '找不到頁面',
        it: 'PAGINA NON TROVATA',
        pl: 'NIE ZNALEZIONO STRONY',
        vi: 'KHÔNG TÌM THẤY TRANG',
        tr: 'SAYFA BULUNAMADI',
        cs: 'STRÁNKA NENALEZENA',
        nl: 'PAGINA NIET GEVONDEN',
      },
      takeMeHomeText: {
        en: 'Take me home',
        zh: '返回首页',
        ja: 'ホームに連れてって',
        ko: '홈으로 이동',
        ru: 'Вернуться на главную',
        ta: 'முகப்புக்குச் செல்லவும்',
        es: 'Volver al inicio',
        fr: 'Retour à l’accueil',
        de: 'Zur Startseite',
        pt: 'Voltar à página inicial',
        'pt-BR': 'Voltar para o início',
        'zh-Hant': '返回首頁',
        'zh-TW': '返回首頁',
        it: 'Torna alla pagina iniziale',
        pl: 'Wróć na stronę główną',
        vi: 'Về trang chủ',
        tr: 'Ana sayfaya dön',
        cs: 'Zpět na úvodní stránku',
        nl: 'Terug naar de startpagina',
      },
    
      errorTitleText: {
        en: 'Something went wrong',
        zh: '页面出了点问题',
        ja: 'エラーが発生しました',
        ko: '문제가 발생했습니다',
        ru: 'Что-то пошло не так',
        ta: 'பிழை ஏற்பட்டது',
        es: 'Algo salió mal',
        fr: 'Une erreur est survenue',
        de: 'Ein Fehler ist aufgetreten',
        pt: 'Ocorreu um erro',
        'pt-BR': 'Algo deu errado',
        'zh-Hant': '發生錯誤',
        'zh-TW': '發生錯誤',
        it: 'Qualcosa è andato storto',
        pl: 'Coś poszło nie tak',
        vi: 'Đã xảy ra lỗi',
        tr: 'Bir sorun oluştu',
        cs: 'Něco se pokazilo',
        nl: 'Er is iets misgegaan',
      },
      errorDescriptionText: {
        en: 'This page could not be loaded. Try reloading it or return to the home page.',
        zh: '页面未能正常加载,请尝试重新加载,或返回首页。',
        ja: 'ページを読み込めませんでした。再読み込みするか、ホームに戻ってください。',
        ko: '페이지를 불러올 수 없습니다. 새로고침하거나 홈으로 돌아가세요.',
        ru: 'Не удалось загрузить страницу. Попробуйте обновить её или вернуться на главную.',
        ta: 'இந்தப் பக்கத்தை ஏற்ற முடியவில்லை. மீண்டும் ஏற்றவும் அல்லது முகப்புப் பக்கத்திற்குத் திரும்பவும்.',
        es: 'No se pudo cargar esta página. Intenta recargarla o vuelve al inicio.',
        fr: 'Impossible de charger cette page. Essayez de la recharger ou retournez à l’accueil.',
        de: 'Diese Seite konnte nicht geladen werden. Lade sie erneut oder kehre zur Startseite zurück.',
        pt: 'Não foi possível carregar esta página. Experimente recarregá-la ou volte à página inicial.',
        'pt-BR':
          'Não foi possível carregar esta página. Tente recarregá-la ou volte para o início.',
        'zh-Hant': '無法載入此頁面。請重新載入或返回首頁。',
        'zh-TW': '無法載入此頁面。請重新載入或返回首頁。',
        it: 'Impossibile caricare questa pagina. Prova a ricaricarla o torna alla pagina iniziale.',
        pl: 'Nie udało się wczytać tej strony. Spróbuj ją odświeżyć lub wróć na stronę główną.',
        vi: 'Không thể tải trang này. Hãy thử tải lại hoặc về trang chủ.',
        tr: 'Bu sayfa yüklenemedi. Sayfayı yeniden yüklemeyi dene veya ana sayfaya dön.',
        cs: 'Tuto stránku se nepodařilo načíst. Zkuste ji načíst znovu nebo se vraťte na úvodní stránku.',
        nl: 'Deze pagina kon niet worden geladen. Probeer de pagina opnieuw te laden of ga terug naar de startpagina.',
      },
      reloadPageText: {
        en: 'Reload page',
        zh: '重新加载',
        ja: '再読み込み',
        ko: '새로고침',
        ru: 'Обновить страницу',
        ta: 'பக்கத்தை மீண்டும் ஏற்றவும்',
        es: 'Recargar página',
        fr: 'Recharger la page',
        de: 'Seite neu laden',
        pt: 'Recarregar a página',
        'pt-BR': 'Recarregar página',
        'zh-Hant': '重新載入頁面',
        'zh-TW': '重新載入頁面',
        it: 'Ricarica la pagina',
        pl: 'Odśwież stronę',
        vi: 'Tải lại trang',
        tr: 'Sayfayı yeniden yükle',
        cs: 'Načíst stránku znovu',
        nl: 'Pagina opnieuw laden',
      },
      errorDetailsText: {
        en: 'Error details',
        zh: '错误详情',
        ja: 'エラーの詳細',
        ko: '오류 세부 정보',
        ru: 'Подробности ошибки',
        ta: 'பிழை விவரங்கள்',
        es: 'Detalles del error',
        fr: 'Détails de l’erreur',
        de: 'Fehlerdetails',
        pt: 'Detalhes do erro',
        'pt-BR': 'Detalhes do erro',
        'zh-Hant': '錯誤詳細資訊',
        'zh-TW': '錯誤詳細資訊',
        it: 'Dettagli dell’errore',
        pl: 'Szczegóły błędu',
        vi: 'Chi tiết lỗi',
        tr: 'Hata ayrıntıları',
        cs: 'Podrobnosti o chybě',
        nl: 'Foutdetails',
      },
    
      promptCopyText: {
        en: 'Copy Prompt',
        zh: '复制 Prompt',
        ja: 'Prompt をコピー',
        ko: '프롬프트 복사',
        ru: 'Скопировать Prompt',
        ta: 'Prompt-ஐ நகலெடு',
        es: 'Copiar prompt',
        fr: 'Copier le prompt',
        de: 'Prompt kopieren',
        pt: 'Copiar prompt',
        'pt-BR': 'Copiar prompt',
        'zh-Hant': '複製提示詞',
        'zh-TW': '複製提示詞',
        it: 'Copia il prompt',
        pl: 'Skopiuj prompt',
        vi: 'Sao chép lời nhắc',
        tr: 'İstemi kopyala',
        cs: 'Zkopírovat prompt',
        nl: 'Prompt kopiëren',
      },
      promptCopiedText: {
        en: 'Copied',
        zh: '已复制',
        ja: 'コピーしました',
        ko: '복사됨',
        ru: 'Скопировано',
        ta: 'நகலெடுக்கப்பட்டது',
        es: 'Copiado',
        fr: 'Copié',
        de: 'Kopiert',
        pt: 'Copiado',
        'pt-BR': 'Copiado',
        'zh-Hant': '已複製',
        'zh-TW': '已複製',
        it: 'Copiato',
        pl: 'Skopiowano',
        vi: 'Đã sao chép',
        tr: 'Kopyalandı',
        cs: 'Zkopírováno',
        nl: 'Gekopieerd',
      },
      promptExpandText: {
        en: 'Expand',
        zh: '展开',
        ja: '展開',
        ko: '펼치기',
        ru: 'Развернуть',
        ta: 'விரிவாக்கு',
        es: 'Expandir',
        fr: 'Développer',
        de: 'Ausklappen',
        pt: 'Expandir',
        'pt-BR': 'Expandir',
        'zh-Hant': '展開',
        'zh-TW': '展開',
        it: 'Espandi',
        pl: 'Rozwiń',
        vi: 'Mở rộng',
        tr: 'Genişlet',
        cs: 'Rozbalit',
        nl: 'Uitklappen',
      },
      promptCollapseText: {
        en: 'Collapse',
        zh: '折叠',
        ja: '折りたたむ',
        ko: '접기',
        ru: 'Свернуть',
        ta: 'சுருக்கு',
        es: 'Contraer',
        fr: 'Réduire',
        de: 'Einklappen',
        pt: 'Recolher',
        'pt-BR': 'Recolher',
        'zh-Hant': '收合',
        'zh-TW': '收合',
        it: 'Comprimi',
        pl: 'Zwiń',
        vi: 'Thu gọn',
        tr: 'Daralt',
        cs: 'Sbalit',
        nl: 'Inklappen',
      },
    } as const satisfies Required<I18nText>;
    
    // cspell:enable
    

    logo

    • Type: string | { dark: string; light: string; width?: number; height?: number }
    • Default: ""

    Site logo. Rspress uses this path for the logo in the upper-left corner of the navbar. In the object form, optional width and height set the intrinsic dimensions (in pixels) for both images; use the source images' dimensions to reserve their aspect ratio and reduce layout shifts. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      logo: '/logo.png',
    });

    Rspress resolves the logo from the public directory. You can also use a CDN URL.

    You can also set different logos for dark and light mode:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      logo: {
        dark: '/logo-dark.png',
        light: '/logo-light.png',
        width: 120,
        height: 32,
      },
    });

    logoHref

    • Type: string
    • Default: /${lang}/

    Custom link for the logo. By default, clicking the logo navigates to the homepage of the current language. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      logo: '/logo.png',
      logoHref: 'https://example.com',
    });

    logoText

    • Type: string
    • Default: ""

    Site logo text. Rspress displays this text in the upper-left corner of the navbar. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      logoText: 'rspress',
    });

    outDir

    • Type: string
    • Default: doc_build

    Custom output directory for built sites. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      outDir: 'doc_build',
    });

    themeDir

    • Type: string
    • Default: theme

    Specifies the custom theme directory. By default, Rspress uses the theme directory under the current working directory as the custom theme directory. You can use themeDir to customize it. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import path from 'path';
    
    export default defineConfig({
      themeDir: path.join(__dirname, 'my-theme'),
    });

    This option supports both relative and absolute paths. Relative paths are resolved from the current working directory.

    For more details on custom themes, see Custom Theme.

    • Type: string | [string, Record<string, string>] | (route) => string | [string, Record<string, string>] | undefined
    • Can be appended per page via frontmatter

    Adds extra elements to the page's HTML <head> in production builds.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      // ... other user config
      head: [
        '<meta name="author" content="John Doe">',
        // or
        ['meta', { name: 'author', content: 'John Doe' }],
        // [htmlTag, { attrName: attrValue, attrName2: attrValue2 }]
        // or
        route => {
          if (route.routePath.startsWith('/jane/'))
            return "<meta name='author' content='Jane Doe'>";
          if (route.routePath.startsWith('/john/'))
            return ['meta', { name: 'author', content: 'John Doe' }];
          // or even skip returning anything
          return undefined;
        },
      ],
    });

    globalStyles

    • Type: string
    • Default: undefined

    Adds global styles from a style file path. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import path from 'path';
    
    export default defineConfig({
      globalStyles: path.join(__dirname, 'styles/global.css'),
    });
    styles/global.css
    :root {
      --rp-c-brand: #f00;
    }

    sitemap

    • Type: boolean | SitemapOptions
    • Default: true

    Generate sitemap.xml in the output directory during production builds. This feature is built into Rspress and does not require a plugin. It also works when ssg is false. Existing sitemap files copied from the public directory are preserved. Generated URLs follow route.cleanUrls.

    Configure siteOrigin so the sitemap contains absolute URLs. Rspress combines siteOrigin, base, and each page's route path:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      siteOrigin: 'https://example.com',
      base: '/docs/',
      // sitemap is enabled by default.
    });

    Set sitemap: false to disable generation, or pass an options object to customize it:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      siteOrigin: 'https://example.com',
      sitemap: {
        defaultChangeFreq: 'weekly',
        defaultPriority: '0.7',
      },
    });

    The options have the following type, exported as SitemapOptions from @rspress/core:

    type ChangeFreq =
      'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
    
    type Priority =
      | '0.0'
      | '0.1'
      | '0.2'
      | '0.3'
      | '0.4'
      | '0.5'
      | '0.6'
      | '0.7'
      | '0.8'
      | '0.9'
      | '1.0';
    
    // https://www.sitemaps.org/protocol.html
    interface Sitemap {
      loc: string;
      lastmod?: string;
      changefreq?: ChangeFreq;
      priority?: Priority;
    }
    
    interface CustomMaps {
      [routePath: string]: Sitemap;
    }
    
    export interface SitemapOptions {
      siteUrl?: string;
      customMaps?: CustomMaps;
      defaultPriority?: Priority;
      defaultChangeFreq?: ChangeFreq;
    }

    sitemap.siteUrl

    • Type: string
    • Default: siteOrigin + base, or base when siteOrigin is not configured

    Override the deployment URL used in sitemap entries. Use an absolute URL that includes the base path, such as https://example.com/docs/. This value takes precedence over siteOrigin and base. Only HTTP(S) URLs without query strings or fragments are accepted.

    If neither sitemap.siteUrl nor siteOrigin is configured, entries use base + routePath and remain relative paths. Configure either value to generate absolute sitemap URLs.

    sitemap.customMaps

    • Type: Record<string, Sitemap>
    • Default: {}

    Override sitemap values for individual pages. Keys are route paths without base, and values override the generated loc, lastmod, changefreq, and priority. By default, lastmod is the source file's modification time. This option customizes existing pages; it does not add routes.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      siteOrigin: 'https://example.com',
      base: '/docs/',
      sitemap: {
        customMaps: {
          '/guide': {
            loc: 'https://example.com/docs/guide',
            lastmod: '2026-01-01',
            changefreq: 'weekly',
            priority: '0.8',
          },
        },
      },
    });

    sitemap.defaultChangeFreq

    • Type: ChangeFreq
    • Default: 'monthly'

    The default changefreq value for each page. Available values are 'always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', and 'never'. Use customMaps to override it for a specific page.

    sitemap.defaultPriority

    • Type: Priority
    • Default: '0.5'

    The default priority value for each page, from '0.0' to '1.0' in increments of 0.1. The root route / uses '1.0'. Use customMaps to override it for a specific page.

    mediumZoom

    • Type: boolean | { selector?: string }
    • Default: true

    Controls whether image zoom is enabled. It is enabled by default; set mediumZoom to false to disable it.

    Image zoom is implemented with the medium-zoom library.

    Example usage:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      // Turn off image zoom
      mediumZoom: false,
      // Configure the CSS selector for images that can be zoomed. The default is '.rspress-doc img'
      mediumZoom: {
        selector: '.rspress-doc img',
      },
    });
    • Type:
    type SearchOptions = {
      searchHooks?: string;
      versioned?: boolean;
      codeBlocks?: boolean;
    };
    Tip

    To exclude an individual page from the search index, set search: false in its frontmatter.

    searchHooks

    • Type: string
    • Default: undefined

    Use searchHooks to add runtime hooks for search. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import path from 'path';
    
    export default defineConfig({
      search: {
        searchHooks: path.join(__dirname, 'searchHooks.ts'),
      },
    });

    For specific hook logic, you can read Customize Search Functions.

    versioned

    • Type: boolean
    • Default: true

    When using multiVersion, a separate search index is created for each version by default, so that search results only include pages from the version the user is currently viewing. Set versioned to false to disable this behavior and include all versions in search results.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      search: {
        versioned: false,
      },
    });

    codeBlocks

    • Type: boolean
    • Default: true

    Whether to include code block content in the search index, which allows users to search code blocks.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      search: {
        codeBlocks: false,
      },
    });

    globalUIComponents

    • Type: (string | [string, object])[]
    • Default: []

    You can register global UI components through the globalUIComponents parameter, for example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import path from 'path';
    
    export default defineConfig({
      globalUIComponents: [path.join(__dirname, 'components', 'MyComponent.tsx')],
    });

    Each globalUIComponents item can be either a component file path string or a tuple. In the tuple form, the first item is the component file path and the second item is the component props. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      globalUIComponents: [
        [
          path.join(__dirname, 'components', 'MyComponent.tsx'),
          {
            foo: 'bar',
          },
        ],
      ],
    });

    When you register global components, Rspress automatically renders these React components in the theme without requiring manual imports.

    Global components can implement many custom features, such as:

    compUi.tsx
    import React from 'react';
    
    // Need a default export
    // Props come from your config
    export default function PluginUI(props?: { foo: string }) {
      return <div>This is a global layout component</div>;
    }

    The component content is then rendered in the theme, for example to add a BackToTop button.

    You can also use a global component to register side effects:

    compSideEffect.tsx
    import { useEffect } from 'react';
    import { useLocation } from '@rspress/core/runtime';
    
    // Need a default export
    export default function PluginSideEffect() {
      const { pathname } = useLocation();
      useEffect(() => {
        // Executed when the component renders for the first time
      }, []);
    
      useEffect(() => {
        // Executed when the route changes
      }, [pathname]);
      return null;
    }

    The component side effects then run in the theme. For example, side effects are useful for:

    • Redirecting specific page routes.
    • Binding click events on page img tags to implement image zoom.
    • Reporting page view data when the route changes.

    multiVersion

    • Type: { default: string; versions: string[] }

    Enable multi-version support with multiVersion. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      multiVersion: {
        default: 'v1',
        versions: ['v1', 'v2'],
      },
    });

    The default parameter is the default version, and the versions parameter is the version list.

    route

    • Type: Object

    Custom route config.

    route.include

    • Type: string[]
    • Default: []

    Adds extra files to the route table. By default, only files in the docs root are included. For example:

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        include: ['other-dir/**/*.{md,mdx}'],
      },
    });

    Note: Strings in the array support glob patterns. The glob expression should be relative to the docs root and include the relevant file extensions.

    Note

    For more flexible page routes and file/content mapping, we recommend using the addPages hook in a custom Rspress plugin.

    route.exclude

    • Type: string[]
    • Default: []

    Exclude some files from the route. For example:

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        exclude: ['custom.tsx', 'component/**/*'],
      },
    });

    Note: Strings in the array support glob patterns. The glob expression should be relative to the docs root.

    route.excludeConvention

    • Type: string[]
    • Default: ['**/_[^_]*']

    A routing convention that makes it easier to keep components in the docs directory. By default, files starting with _ are excluded.

    If you really need some routes starting with _, you can adjust this rule, for example, set it to exclude only files starting with _fragment-:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        excludeConvention: ['**/_fragment-*'],
      },
    });

    route.extensions

    • Type: string[]
    • Default: ['.js', '.jsx', '.ts', '.tsx', '.md', '.mdx']

    File extensions to include in the route table. By default, Rspress includes all 'js', 'jsx', 'ts', 'tsx', 'md', and 'mdx' files. To customize the extensions, use this option:

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        extensions: ['.md', '.mdx'],
      },
    });

    route.cleanUrls

    • Type: Boolean
    • Default: true (false before v2.1.0)

    Generates URLs without file extensions. Set cleanUrls to false to keep the .html suffix.

    Server Support Required

    Enabling this may require additional configuration on your hosting platform. For it to work, your server must be able to serve /foo.html when visiting /foo without a redirect.

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        cleanUrls: false,
      },
    });

    route.cleanUrlsRedirect

    • Type: Boolean
    • Default: true

    When enabled, Rspress normalizes non-canonical browser URLs during client startup, using the actual matched route as the source of truth. The target format follows route.cleanUrls.

    route.cleanUrls controls the preferred URL format used by generated links, while route.cleanUrlsRedirect only normalizes the browser address bar.

    Client-side fallback

    This option runs after the requested page HTML and client runtime have loaded. It uses history.replaceState and does not return an HTTP 301/308 response, so it cannot fully replace a server-side or CDN canonical redirect, especially for SEO. The hosting platform must still serve the correct Rspress page for the requested URL variant. Prefer a server-side redirect when available.

    With cleanUrls: true

    Regular page routes omit the trailing slash, while directory index routes retain it.

    Incoming URLMatched routeBrowser URL update
    /file/fileNo update
    /file.html/filereplaceState to /file
    /file//filereplaceState to /file
    /file/index/filereplaceState to /file
    /file/index.html/filereplaceState to /file
    /folder/folder/replaceState to /folder/
    /folder.html/folder/replaceState to /folder/
    /folder//folder/No update
    /folder/index/folder/replaceState to /folder/
    /folder/index.html/folder/replaceState to /folder/

    With cleanUrls: false

    Regular page routes use .html, while directory index routes use /index.html.

    Incoming URLMatched routeBrowser URL update
    /file/filereplaceState to /file.html
    /file.html/fileNo update
    /file//filereplaceState to /file.html
    /file/index/filereplaceState to /file.html
    /file/index.html/filereplaceState to /file.html
    /folder/folder/replaceState to /folder/index.html
    /folder.html/folder/replaceState to /folder/index.html
    /folder//folder/replaceState to /folder/index.html
    /folder/index/folder/replaceState to /folder/index.html
    /folder/index.html/folder/No update

    For example, both /zh/guide/start/introduction.html and /zh/guide/start/introduction/index.html match /zh/guide/start/introduction; the final URL follows the configured cleanUrls format without losing the locale prefix.

    The canonical URL formats align with Cloudflare's HTML handling. However, Cloudflare performs server-side HTTP redirects, while this option only updates the URL in the browser.

    Set cleanUrlsRedirect to false to disable browser URL normalization:

    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        cleanUrlsRedirect: false,
      },
    });

    route.localeRedirect

    • Type: 'auto' | 'never' | 'only-default-lang'
    • Default: 'auto'

    Controls how first-time visitors are redirected to the closest configured locale based on window.navigator.language:

    • auto: Redirect from any locale to the closest configured locale.
    • never: Disable automatic locale redirects.
    • only-default-lang: Redirect only when the visitor opens the default locale.
    Prefer server-side redirects

    This option performs the redirect in the browser. For production sites, prefer handling locale negotiation and redirects on the server or at the CDN edge when possible. This redirects visitors before HTML is delivered and does not depend on client-side JavaScript.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        localeRedirect: 'never',
      },
    });

    route.useTransitions

    • Type: Boolean
    • Default: true

    Enable concurrent, optimized routing for internal links rendered by Rspress' default Link component. This covers links in markdown and MDX content, as well as default theme navigation links such as sidebar items.

    By default, this option is enabled. Internal page transitions are wrapped inside React's startTransition unless you explicitly set useTransitions to false. This prevents the heavy rendering of new page content from blocking user input, keeping the page responsive and interactive during navigation.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        useTransitions: false,
      },
    });
    • Type: Boolean
    • Default: true

    By default, Rspress' Link component prefetches resources for the matching route when users hover over internal links, and it applies the same behavior on touch devices. This is a performance optimization. Set this option to false to disable it.

    Tip

    In development, link prefetching is designed to work together with dev.lazyCompilation, which Rspress enables by default. Lazy compilation improves startup speed by compiling pages only when they are visited, while link prefetching starts compiling the target route on hover to reduce the wait when the target route is opened for the first time.

    Example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      route: {
        prefetchLink: false,
      },
    });

    ssg

    • Type: boolean | { experimentalWorker?: boolean; experimentalLoose?: boolean; }
    • Default: true

    Controls whether page content is rendered into HTML at build time. Rspress enables SSG by default.

    Set ssg: false to generate HTML shells for client-side rendering.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      ssg: false,
    });
    Tip

    Both SSG and SSG-MD require source code to compile under SSR. Code that is incompatible with SSR will cause the build to fail. You can try:

    1. Make your code SSR-compatible. See Common issues and solutions in the SSG guide.

    2. If your code does not support SSR, set both ssg: false and llms: false:

      rspress.config.ts
      import { defineConfig } from '@rspress/core';
      
      export default defineConfig({
        ssg: false,
        llms: false,
      });

    experimentalWorker

    • Type: boolean
    • Default: false

    When enabled, Rspress uses workers to accelerate SSG and reduce memory usage. This is suitable for large documentation sites and is based on tinypool.

    experimentalExcludeRoutePaths

    • Type: (string | RegExp)[]
    • Default: []

    Excludes selected pages from SSG so they use CSR HTML directly. This can help large documentation sites bypass SSG errors on a small number of pages, but it is not recommended as a default choice.

    This option only affects SSG; it does not exclude pages from SSG-MD. If excluded pages are incompatible with SSR, make them SSR-compatible or set llms: false to disable SSG-MD.

    replaceRules

    • Type: { search: string | RegExp; replace: string; }[]
    • Default: []

    You can set text replacement rules for the entire site through replaceRules. The rules will apply to everything including _meta.json files, frontmatter configurations, and document content and titles.

    rspress.config.ts
    export default {
      replaceRules: [
        {
          search: /foo/g,
          replace: 'bar',
        },
      ],
    };

    languageParity

    • Type: Object

    Scans md and mdx files in the docs root to detect missing language versions and protect language parity.

    languageParity.enabled

    • Type: boolean
    • Default: false

    Whether to enable language parity checks.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      languageParity: {
        enabled: true,
      },
    });

    languageParity.include

    • Type: string[]
    • Default: []

    Specifies which folders to check. By default, all files in the docs root are checked. Paths should be relative to each language directory. For example:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      languageParity: {
        // `posts/foods` and `articles` folders under the zh/en language directories
        include: ['posts/foods', 'articles'],
      },
    });

    languageParity.exclude

    • Type: string[]
    • Default: []

    Excludes certain folders and files from the checks.

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    
    export default defineConfig({
      languageParity: {
        exclude: ['excluded-directory', 'articles/secret.md'],
      },
    });