Built-in Search
Built-in document search of Fumadocs
Fumadocs supports searching document based on Orama.
As the built-in search of Fumadocs, It is the default but also recommended option since it's easier to setup and totally free.
Search Server
You can create the search route handler from the source object, or search indexes.
From Source
Create a route handler from source object.
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
export const { GET } = createFromSource(source);
From Search Indexes
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', {
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,
})),
});
Special Languages
If your language is not on the Orama Supported Languages list, you have to configure them manually:
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
import { createTokenizer } from '@orama/tokenizers/mandarin';
export const { GET } = createFromSource(source, {
localeMap: {
// you can customise search configs for specific locales, like:
// [locale]: Orama options
cn: {
components: {
tokenizer: createTokenizer(),
},
search: {
threshold: 0,
tolerance: 0,
},
},
},
});
import { source } from '@/lib/source';
import { createFromSource } from 'fumadocs-core/search/server';
import { createTokenizer } from '@orama/tokenizers/mandarin';
// example for Mandarin
export const { GET } = createFromSource(source, {
components: {
tokenizer: createTokenizer(),
},
search: {
threshold: 0,
tolerance: 0,
},
});
See Orama Docs for more details.
Search Client
You can search documents using:
-
Fumadocs UI: The built-in Search UI supports it out-of-the-box.
-
Search Client:
import { useDocsSearch } from 'fumadocs-core/search/client'; const client = useDocsSearch({ type: 'fetch', });
Prop Type Default api?
string
- type
"fetch"
-
Tag Filter
Support filtering 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'; // Pass `tag` in your custom search dialog const client = useDocsSearch( { type: 'fetch', }, undefined, // locale code, can be `undefined` 'tag', );
Internationalization
import { i18n } from '@/lib/i18n';
import { loader } from 'fumadocs-core/source';
// You only need i18n option on source object.
export const source = loader({
i18n,
});
import { source } from '@/lib/source';
import { createI18nSearchAPI } from 'fumadocs-core/search/server';
import { i18n } from '@/lib/i18n';
export const { GET } = createI18nSearchAPI('advanced', {
i18n,
indexes: source.getLanguages().flatMap(({ language, pages }) =>
pages.map((page) => ({
title: page.data.title,
description: page.data.description,
structuredData: page.data.structuredData,
id: page.url,
url: page.url,
locale: language,
})),
),
});
Update Search Client
For Fumadocs UI
You can ignore this, Fumadocs UI handles this when you have i18n configured correctly.
Add locale
to the search client, this will only allow pages with specified locale to be searchable by the user.
const { search, setSearch, query } = useDocsSearch(
{
type: 'fetch',
},
locale,
);
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: See Static Export guide.
-
Search Client:
On your search client, use
static
instead offetch
.import { useDocsSearch } from 'fumadocs-core/search/client'; const client = useDocsSearch({ type: 'static', });
Prop Type Default initOrama?
((locale?: string | undefined) => AnyOrama | Promise<AnyOrama>)
- from?
string
- type
"static"
-
Be Careful
Static Search requires clients to download the exported search indexes. For large docs sites, its size can be really big.
Especially with i18n (e.g. Chinese tokenizers), the bundle size of tokenizers can exceed ~500MB. You should use 3rd party solutions like Algolia for these cases.
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?