Built-in Search
Built-in document search of Fumadocs
Fumadocs supports document search with Orama, It is the default but also the recommended option since it can be self-hosted and totally free.
Setup
Host the server for handling search requests.
Create a route handler from source object.
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
export const { GET } = createFromSource(source, {
// https://docs.orama.com/open-source/supported-languages
language: 'english',
});
Pass search indexes to the function, each index needs a structuredData
field.
Usually, it is provided by your content source (e.g. Fumadocs MDX). You can also extract it from Markdown/MDX document using the Remark Structure plugin.
import { source } from '@/lib/source';
import { createSearchAPI } from 'fumadocs-core/search/server';
export const { GET } = createSearchAPI('advanced', {
language: 'english',
indexes: source.getPages().map((page) => ({
title: page.data.title,
description: page.data.description,
url: page.url,
id: page.url,
structuredData: page.data.structuredData,
})),
});
Index with the raw content of document (unrecommended).
import { allDocs } from 'content-collections';
import { createSearchAPI } from 'fumadocs-core/search/server';
export const { GET } = createSearchAPI('simple', {
indexes: allDocs.map((docs) => ({
title: docs.title,
content: docs.content, // Raw Content
url: docs.url,
})),
});
You can search documents using:
- Fumadocs UI: Supported out-of-the-box, see Search UI for details.
- Search Client:
import { useDocsSearch } from 'fumadocs-core/search/client';
const client = useDocsSearch({
type: 'fetch',
});
Prop | Type | Default |
---|---|---|
locale? | string | - |
tag? | string | string[] | - |
api? | string | '/api/search' |
type | "fetch" | - |
Tag Filter
Support filtering results by tag, it's useful for implementing multi-docs similar to this documentation.
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
export const { GET } = createFromSource(source, {
buildIndex(page) {
return {
title: page.data.title,
description: page.data.description,
url: page.url,
id: page.url,
structuredData: page.data.structuredData,
// use your desired value, like page.slugs[0]
tag: '<value>',
};
},
});
and update your search client:
- Fumadocs UI: Configure Tag Filter on Search UI.
- Search Client: pass a tag to the hook.
import { useDocsSearch } from 'fumadocs-core/search/client';
const client = useDocsSearch({
type: 'fetch',
tag: '<value>',
});
Static Export
To work with Next.js static export, use staticGET
from search server.
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
// it should be cached forever
export const revalidate = false;
export const { staticGET: GET } = createFromSource(source);
staticGET
is also available on createSearchAPI
.
and update your search clients:
-
Fumadocs UI: use static client on Search UI.
-
Search Client: use
static
instead offetch
.import { useDocsSearch } from 'fumadocs-core/search/client'; const client = useDocsSearch({ type: 'static', });
Prop Type Default locale?
string
- tag?
string | string[]
- initOrama?
((locale?: string | undefined) => AnyOrama | Promise<AnyOrama>)
- from?
string
'/api/search'
type
"static"
-
Be Careful
Static Search requires clients to download the exported search indexes. For large docs sites, it can be expensive.
You should use cloud solutions like Orama Cloud or Algolia for these cases.
Internationalization
Make sure your language is on the Orama Supported Languages list.
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
export const { GET } = createFromSource(source, {
localeMap: {
// [locale]: Orama options
ru: { language: 'russian' },
en: { language: 'english' },
},
});
For Chinese & Japanese, they require additional configurations:
npm install @orama/tokenizers
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
import { createTokenizer } from '@orama/tokenizers/mandarin';
export const { GET } = createFromSource(source, {
localeMap: {
// [locale]: Orama options
cn: {
components: {
tokenizer: createTokenizer(),
},
search: {
threshold: 0,
tolerance: 0,
},
},
},
});
and update your search clients:
- Fumadocs UI: No changes needed, Fumadocs UI handles this when you have i18n configured correctly.
- Search Client:
Add
locale
to the search client, this will only allow pages with specified locale to be searchable by the user.
import { useDocsSearch } from 'fumadocs-core/search/client';
const { search, setSearch, query } = useDocsSearch({
type: 'fetch',
locale: 'cn',
});
Headless
You can host the search server on other backend such as Express and Elysia.
import { initAdvancedSearch } from 'fumadocs-core/search/server';
const server = initAdvancedSearch({
// you still have to pass indexes
});
server.search('query', {
// you can specify `locale` and `tag` here
});
How is this guide?
Last updated on