SveltePress default theme provides built-in Local Search powered by Pagefind out of the box with zero configuration. In addition, the default theme supports Algolia DocSearch through docsearch and custom search components through search, including @sveltepress/meilisearch.

Local Search (Default)

Local search is enabled by default with zero configuration. When building your documentation site (pnpm build), SveltePress automatically runs Pagefind to index all static HTML pages and bundles the search assets into /pagefind/.

Features

  • Zero-config: Works immediately without external API keys or remote indexing services.
  • Offline & Static: Runs entirely in the browser via WebAssembly, fast and privacy-friendly.
  • Multi-locale support: Automatically detects <html lang="..."> and filters search queries by the active page language.
  • Keyboard navigation: Opens via Cmd+K (macOS) or Ctrl+K (Windows/Linux), navigate with Arrow keys, select with Enter, close with Escape.
  • Development notice: In development mode (pnpm dev), searching displays an informative notice explaining that the full index is created during production build.

Disabling Local Search

If you want to disable search entirely:

vite.config.(js|ts)
import { const defaultTheme: ThemeDefaultdefaultTheme } from '@sveltepress/theme-default'
import { const sveltepress: (options?: SveltepressVitePluginOptions) => PluginOptionsveltepress } from '@sveltepress/vite'
import { function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
} from 'vite'
export default function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
({
UserConfig.plugins?: PluginOption[] | undefined

Array of vite plugins to use.

plugins
: [
function sveltepress(options?: SveltepressVitePluginOptions): PluginOptionsveltepress({ SveltepressVitePluginOptions.theme?: ResolvedTheme | undefinedtheme: function defaultTheme(themeOptions?: DefaultThemeOptions | undefined): ResolvedThemedefaultTheme({ DefaultThemeOptions.search?: string | boolean | Component<{}, {}, string> | undefinedsearch: false, }), }), ], })
ts

You can also disable the build-time indexer in the Vite plugin:

vite.config.(js|ts)
import { const sveltepress: (options?: SveltepressVitePluginOptions) => PluginOptionsveltepress } from '@sveltepress/vite'

function sveltepress(options?: SveltepressVitePluginOptions): PluginOptionsveltepress({
  SveltepressVitePluginOptions.pagefind?: boolean | PagefindOptions | undefined

Options for Pagefind static local search indexing. Set to false to disable automatic post-build indexing.

pagefind
: false,
})
ts

Algolia DocSearch

Pass a docsearch config object to defaultTheme to use Algolia DocSearch instead of the default local search in the navbar.

Required fields are appId, apiKey, and indexName. Every other DocSearch option is also accepted.

vite.config.(js|ts)
import { const defaultTheme: ThemeDefaultdefaultTheme } from '@sveltepress/theme-default'
import { const sveltepress: (options?: SveltepressVitePluginOptions) => PluginOptionsveltepress } from '@sveltepress/vite'
import { function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
} from 'vite'
export default function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
({
UserConfig.plugins?: PluginOption[] | undefined

Array of vite plugins to use.

plugins
: [
function sveltepress(options?: SveltepressVitePluginOptions): PluginOptionsveltepress({ SveltepressVitePluginOptions.theme?: ResolvedTheme | undefinedtheme: function defaultTheme(themeOptions?: DefaultThemeOptions | undefined): ResolvedThemedefaultTheme({ DefaultThemeOptions.docsearch?: Omit<DocSearchProps, "theme" | "container"> | undefineddocsearch: { appId: string

Algolia application id used by the search client.

appId
: 'YOUR_APP_ID',
apiKey: string

Public api key with search permissions for the index.

apiKey
: 'YOUR_SEARCH_API_KEY',
indexName?: string | undefined

Name of the algolia index to query.

@deprecatedindexName will be removed in a future version. Please use indices property going forward.
indexName
: 'YOUR_INDEX_NAME',
}, }), }), ], })
ts
Apply for DocSearch

DocSearch is free for open-source documentation sites. Apply at docsearch.algolia.com.

Meilisearch

@sveltepress/meilisearch is the supported Meilisearch search component. Install it first:

npm install --save @sveltepress/meilisearch
sh
yarn add @sveltepress/meilisearch
sh
pnpm install @sveltepress/meilisearch
sh
bun add @sveltepress/meilisearch
sh

Create a wrapper that provides your Meilisearch connection settings:

src/lib/MeilisearchSearch.svelte
<script lang="ts">
  import 
type Search = SvelteComponent<Record<string, any>, any, any>
const Search: LegacyComponentType
Search
from '@sveltepress/meilisearch/Search.svelte'
</script> <const Search: LegacyComponentTypeSearch host: stringhost="https://search.example.com" apiKey: stringapiKey="YOUR_SEARCH_ONLY_KEY" indexName: stringindexName="docs" />
svelte

Then pass the wrapper path to the default theme's custom-search hook:

vite.config.(js|ts)
import { const defaultTheme: ThemeDefaultdefaultTheme } from '@sveltepress/theme-default'

function defaultTheme(themeOptions?: DefaultThemeOptions | undefined): ResolvedThemedefaultTheme({
  DefaultThemeOptions.search?: string | boolean | Component<{}, {}, string> | undefinedsearch: '/src/lib/MeilisearchSearch.svelte',
})
ts

The component queries an existing Meilisearch index; it does not build the index for you. Each record should provide id, title, content, and either url or path. Use a search-only API key in browser code.

Production builds

A custom search source path is bundled into static production builds: the theme resolves the configured .svelte path at build time and loads it as a lazy chunk, so no extra runtime configuration is needed. Configure the wrapper as a source path (as above). Passing a component object directly is not supported — theme options are serialized to JSON for the client, so objects are dropped. If a production deployment shows no search, make sure search is a source-path string.

For another search provider, implement the same search hook with your own Svelte wrapper. Search precedence is: custom search component > explicit docsearch > default LocalSearch.

Search across locales and versions

When your site combines i18n locales with version management, search stays per-locale and per-version, and the crawler-facing outputs follow the same URL scheme the site serves (/, /zh/, /bn/, /v/<id>/…, /zh/v/<id>/…).

Locale-aware search

Each locale carries its own theme options, so give each locale its own DocSearch index — the pre-i18n documentation site used one index per language:

vite.config.(js|ts)
import { const defaultTheme: ThemeDefaultdefaultTheme } from '@sveltepress/theme-default'
import { const sveltepress: (options?: SveltepressVitePluginOptions) => PluginOptionsveltepress } from '@sveltepress/vite'
import { function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
} from 'vite'
export default function defineConfig(config: UserConfig): UserConfig (+5 overloads)

Type helper to make it easier to use vite.config.ts accepts a direct

UserConfig

object, or a function that returns it. The function receives a

ConfigEnv

object.

defineConfig
({
UserConfig.plugins?: PluginOption[] | undefined

Array of vite plugins to use.

plugins
: [
function sveltepress(options?: SveltepressVitePluginOptions): PluginOptionsveltepress({ SveltepressVitePluginOptions.theme?: ResolvedTheme | undefinedtheme: function defaultTheme(themeOptions?: DefaultThemeOptions | undefined): ResolvedThemedefaultTheme({ // Site-level options shared by every locale (logo, github, pwa, ...) }), SveltepressVitePluginOptions.locales?: LocalesConfig<any> | undefined

Multi-locale site configuration keyed by URL prefix ('/' for the default locale, '/zh/', '/bn/', ...). Each entry carries that locale's lang, a user-facing label for the switcher, and its full theme options.

When omitted the site stays single-locale and behavior is unchanged.

locales
: {
'/': { LocaleConfig<any>.lang: string

BCP 47 language tag, e.g. 'en', 'zh-CN', 'bn'.

lang
: 'en',
LocaleConfig<any>.label: string

User-facing label rendered in the language switcher.

label
: 'English',
LocaleConfig<any>.theme: any

The locale's full theme options.

theme
: {
docsearch: {
    appId: string;
    apiKey: string;
    indexName: string;
}
docsearch
: {
appId: stringappId: 'YOUR_APP_ID', apiKey: stringapiKey: 'YOUR_SEARCH_API_KEY', indexName: stringindexName: 'sveltepress', }, }, }, '/zh/': { LocaleConfig<any>.lang: string

BCP 47 language tag, e.g. 'en', 'zh-CN', 'bn'.

lang
: 'zh',
LocaleConfig<any>.label: string

User-facing label rendered in the language switcher.

label
: '中文',
LocaleConfig<any>.theme: any

The locale's full theme options.

theme
: {
docsearch: {
    appId: string;
    apiKey: string;
    indexName: string;
}
docsearch
: {
appId: stringappId: 'YOUR_APP_ID', apiKey: stringapiKey: 'YOUR_SEARCH_API_KEY', indexName: stringindexName: 'cn', }, }, }, }, }), ], })
ts
Expand code

The Navbar remounts the DocSearch widget whenever the active index or version changes, so switching locale or version queries the right index.

Version-aware search

A version in the manifest may carry search metadata. While a reader is on that historical version's pages (/v/<id>/…), the theme switches DocSearch to the configured indexName and merges facetFilters into the query:

sveltepress.versions.json
{
  "versions": [
    {
      "id": "2026-08-28",
      "search": {
        "indexName": "sveltepress-v2026-08-28",
        "facetFilters": ["version:2026-08-28"]
      }
    }
  ]
}
json

Keep the crawler's facet tags in sync with this metadata.

Historical Local Search vs DocSearch

Historical versions without a search object show "Search is not available for this documentation version." for DocSearch and custom search components only. Built-in Local Search still loads the frozen Pagefind index under that version's /pagefind/ path (via syncHistoricalPagefind on release) and does not require search metadata.

Crawling and result URLs

The generated sitemap.xml lists every locale's current pages and every eligible historical version page with hreflang alternates; EOL history is excluded unless the version opts out (noIndex: false), and every version page emits its own rel="canonical" link. Index records must point at these real, prefixed URLs — a Chinese record's url is /zh/guide/…, a frozen version's is /v/2026-08-28/guide/….

Custom search components

The Navbar renders a custom search component only when search is available for the current route, remounts it per version, and passes it two props:

  • version — the active version object ({ id, label, status, … }), or the current version on unprefixed pages.
  • versionSearch — the version's search metadata ({ indexName?, facetFilters? }), or null.

When your index stores multiple versions, filter results by the facets in versionSearch. Record URLs must be the full prefixed routes. No locale prop is passed: if you keep one index per locale, read the locale from location.pathname yourself.