Typesense Search
Integrate Typesense Search with Fumadocs
This is a community-maintained integration.
Setup
Install Dependencies
npm install typesense typesense-fumadocs-adapterStart Typesense Server
You can either self-host the Typesense server or use their cloud service. Follow their getting started guide to set up your server, and store its credentials in .env.local (VITE_ instead of NEXT_PUBLIC_ outside Next.js):
NEXT_PUBLIC_TYPESENSE_URL="server URL"
NEXT_PUBLIC_TYPESENSE_SEARCH_KEY="search-only API key"
TYPESENSE_API_KEY="API key with write access"Sync Dataset
Export the search indexes with a pre-rendered static.json route, and sync them to Typesense with a script after each build:
import { source } from '@/lib/source';
import type { DocumentRecord } from 'typesense-fumadocs-adapter';
async function getDocuments() {
const documents: DocumentRecord[] = [];
for (const page of source.getPages()) {
documents.push({
_id: page.url,
structured: page.data.structuredData,
url: page.url,
title: page.data.title,
description: page.data.description,
locale: page.locale,
});
}
return documents;
}
export const revalidate = false;
export async function GET() {
return Response.json(await getDocuments());
}
import * as fs from 'node:fs/promises';
import { type DocumentRecord, sync } from 'typesense-fumadocs-adapter';
import { Client } from 'typesense';
const records = JSON.parse(await fs.readFile('.next/server/app/static.json.body', 'utf-8')) as DocumentRecord[];
const client = new Client({
nodes: [{ url: process.env.NEXT_PUBLIC_TYPESENSE_URL! }],
apiKey: process.env.TYPESENSE_API_KEY!,
connectionTimeoutSeconds: 60 * 15,
});
await sync(client, {
typesenseCollectionName: 'docs',
documents: records,
});
console.log(`search updated: ${records.length} records`);
{
"scripts": {
"build": "next build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
}
}The build script syncs on every build, set the same variables on your deployment platform.
Search UI
To implement the search UI, you can either:
-
Build your own search UI with the Typesense search client hook.
import { Client } from 'typesense'; import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client'; const client = new Client({ nodes: [{ url: 'YOUR_TYPESENSE_SERVER_URL' }], apiKey: 'YOUR_TYPESENSE_SEARCH_ONLY_API_KEY', }); const { search, setSearch, query } = useTypesenseSearch({ typesenseCollectionName: 'docs', client, });
Options
Tag Filter
To configure tag filtering, add a tag value to the documents in the static.json route:
documents.push({
// other fields...
tag: '<your value>',
});And update your search client:
-
Fumadocs UI: Enable Tag Filter on Search UI.
-
Search Client: You can add the tag filter like:
import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client'; const { search, setSearch, query } = useTypesenseSearch({ tag: '<your tag value>', // ... });
Internationalization (i18n)
Documents include the locale of their pages, pass locale to the search client:
import { useI18n } from 'fumadocs-ui/contexts/i18n';
import { useTypesenseSearch } from 'typesense-fumadocs-adapter/client';
const { locale } = useI18n();
const { search, setSearch, query } = useTypesenseSearch({
locale,
// other fields...
});Under the hood, Typesense will create separate collections for each locale. The collection name is appended with the _{locale} suffix (e.g., docs_en, docs_fr).
How is this guide?
Last updated on
