How can I implement a custom search in fumadocs?

dev
9f06196UI: fix `footer.children` props
This post might have stale content, as dev is 23 commits ahead.
Avatar of KollerKollerposted

How can implement a custom search in fumadocs?

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

I'll help you understand how to implement custom search in fumadocs. Let me explore the codebase to find relevant information.

Now let me look at the core search implementation and search context:

Let me explore the search directory:

Now let me look at the key files:

Now let me check the search dialog components and look for examples:

Let me look for documentation or examples about custom search:

Great! Let me look at the documentation:

Perfect! Now let me check what the useDocsSearch hook supports and look at the default search dialog implementation:

Let me try again with the fetch file:

Perfect! Now let me look at more client examples to give a comprehensive answer:

Perfect! Now I have a comprehensive understanding. Let me create a summary document for the user:

##How to Implement Custom Search in Fumadocs

Based on the source code, there are several ways to implement custom search in Fumadocs depending on your needs:

###1. Replace the Search Dialog UI (Simplest)

If you want to keep the built-in search functionality but customize the UI, you can provide a custom SearchDialog component to the RootProvider:

'use client';
import { RootProvider } from 'fumadocs-ui/provider/next';
import SearchDialog from '@/components/my-search-dialog';

export default function Layout({ children }: { children: ReactNode }) {
  return (
    <RootProvider search={{ SearchDialog }}>
      {children}
    </RootProvider>
  );
}

The custom dialog must accept SharedProps:

'use client';
import { useDocsSearch } from 'fumadocs-core/search/client';
import {
  SearchDialog,
  SearchDialogClose,
  SearchDialogContent,
  SearchDialogHeader,
  SearchDialogIcon,
  SearchDialogInput,
  SearchDialogList,
  SearchDialogOverlay,
  type SharedProps,
} from 'fumadocs-ui/components/dialog/search';
import { useI18n } from 'fumadocs-ui/contexts/i18n';

export default function MySearchDialog(props: SharedProps) {
  const { locale } = useI18n();
  const { search, setSearch, query } = useDocsSearch({
    type: 'fetch', // or 'static'
    locale,
  });

  return (
    <SearchDialog search={search} onSearchChange={setSearch} isLoading={query.isLoading} {...props}>
      <SearchDialogOverlay />
      <SearchDialogContent>
        <SearchDialogHeader>
          <SearchDialogIcon />
          <SearchDialogInput />
          <SearchDialogClose />
        </SearchDialogHeader>
        <SearchDialogList items={query.data !== 'empty' ? query.data : null} />
      </SearchDialogContent>
    </SearchDialog>
  );
}

###2. Use Different Search Clients

Fumadocs supports multiple search backends via the useDocsSearch() hook:

Fetch (default - local API search):

const { search, setSearch, query } = useDocsSearch({
  type: 'fetch',
  api: '/api/search', // your search endpoint
  locale,
  tag, // optional tag filter
  delayMs: 100,
});

Algolia:

import { liteClient } from 'algoliasearch/lite';

const { search, setSearch, query } = useDocsSearch({
  type: 'algolia',
  indexName: 'your-index',
  client: liteClient('appId', 'searchKey'),
  tag,
  locale,
});

Orama Cloud:

const { search, setSearch, query } = useDocsSearch({
  type: 'orama-cloud',
  indexId: 'your-index-id',
  apiKey: 'your-api-key',
  tag,
});

Static (client-side only):

const { search, setSearch, query } = useDocsSearch({
  type: 'static',
  from: '/api/search', // exports the database
  tag,
});

Mixedbread:

const { search, setSearch, query } = useDocsSearch({
  type: 'mixedbread',
  apiKey: 'your-key',
  storeId: 'your-store',
});

###3. Completely Custom Search Implementation

If you need full control, create a custom component that doesn't use useDocsSearch:

'use client';
import { useState } from 'react';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';

export default function CustomSearchDialog({ open, onOpenChange }: SharedProps) {
  const [query, setQuery] = useState('');
  
  const handleSearch = async (q: string) => {
    // Your custom search logic here
    const results = await myCustomSearchFunction(q);
    return results;
  };

  return (
    <dialog open={open} onClose={() => onOpenChange(false)}>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />
      {/* Render your custom results */}
    </dialog>
  );
}

###4. Customize Search Server-Side (Backend)

For the API route, use createSearchAPI:

import { createFromSource } from 'fumadocs-core/search/server';
import { getPages } from '@/app/source';

export const { GET, POST } = createFromSource(
  getPages(),
  {
    // Customize search options
    search: {
      // ... Orama search options
    },
  }
);

Or with advanced indexing:

import { createSearchAPI } from 'fumadocs-core/search/server';

export const GET = createSearchAPI('advanced', {
  indexes: async () => {
    return [
      {
        id: 'page-1',
        title: 'My Page',
        content: 'Page content...',
        url: '/docs/page-1',
        structuredData: { /* from MDX */ },
      },
    ];
  },
}).GET;

###5. Customize Hotkeys

<RootProvider
  search={{
    hotKey: [
      {
        display: 'S',
        key: 's',
      },
      {
        display: '⌘',
        key: (e) => e.metaKey || e.ctrlKey,
      },
    ],
  }}
>
  {children}
</RootProvider>

###6. Customize Search Dialog Options

<RootProvider
  search={{
    options: {
      links: [['Home', '/']],
      defaultTag: 'docs',
      tags: [
        { name: 'Docs', value: 'docs' },
        { name: 'API', value: 'api' },
      ],
      allowClear: true,
      delayMs: 200,
    },
  }}
>
  {children}
</RootProvider>

###Key Interfaces

  • SharedProps: { open: boolean; onOpenChange: (open: boolean) => void }
  • SortedResult: The search result type with id, type ('page', 'heading', 'text'), url, content, etc.
  • useDocsSearch return: { search: string; setSearch: (v: string) => void; query: { isLoading: boolean; data?: SortedResult[] | 'empty'; error?: Error } }

This gives you flexibility from simple UI customization to complete custom search implementations!

Avatar of KollerKollercommented

What search clients do you recommend? give me a comparasion

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

I'll search for information about the different search clients available in fumadocs and provide you with a comparison.

Let me explore the docs structure differently:

Great! Now let me read these search integration docs:

Now let me get the other search integrations:

Perfect! Now let me check for any additional info on setup and costs:

Great! Now let me compile a comprehensive comparison. Let me also check the documentation for any final details:

Perfect! Now I have all the information needed. Let me create a comprehensive comparison:

##Search Clients Comparison for Fumadocs

Based on the source code and documentation, here's a detailed comparison of the search solutions supported by fumadocs:


##1. Orama (Built-in/Default) ⭐ Recommended

###Pros:

  • Free & Self-hosted - No costs, fully open-source
  • Official recommendation - Fumadocs explicitly recommends this as default
  • No external dependencies - Keeps your data private
  • Easiest setup - Minimal configuration needed
  • Full-text & Vector search - Supports both search modes
  • Tag filtering - Built-in support for filtering
  • Multi-language support - Configurable language stemming
  • i18n friendly - Easy internationalization

###Cons:

  • Client-side indexing needed - Requires exporting database
  • Limited to your infra - Scales with your server capacity
  • No managed solution - You manage everything

###Setup Complexity: Easy

// From your source
import { createFromSource } from 'fumadocs-core/search/server';

export const { GET } = createFromSource(getPages());

###Cost: Free 💰

###Best For:

  • Small to medium docs sites
  • Privacy-conscious teams
  • Self-hosted deployments
  • Budget-conscious projects

##2. Algolia 🔍

###Pros:

  • Enterprise-grade - Mature, widely used platform
  • Excellent performance - Lightning-fast search at scale
  • Advanced features - Rich analytics, synonyms, custom ranking
  • Well-documented - Extensive guides and examples
  • Tag filtering - Good faceting support

###Cons:

  • Expensive - Complex pricing structure (costs can escalate)
  • Free tier limited - Requires logo display on free plan
  • External dependency - Vendor lock-in
  • Setup complexity - Requires syncing via scripts
  • Per-request billing - Costs grow with usage

###Setup Complexity: Medium ⭐⭐

// Need to sync docs regularly
import { sync } from 'fumadocs-core/search/algolia';
await sync(client, { indexName: 'docs', documents: records });

###Cost: $25+/month (variable based on usage) 💸

  • Starts around $25/month for build tier
  • Enterprise features require higher tiers
  • Per-search-request billing model

###Best For:

  • Large-scale doc sites
  • Enterprise requirements
  • Complex search features needed
  • Teams with budget

##3. Orama Cloud ☁️

###Pros:

  • Hosted solution - No server management needed
  • Two deployment options - REST API or Web Crawler
  • Easier than Algolia - Simpler pricing
  • Web crawler option - Auto-index without setup
  • Still from Orama team - Same company as default option

###Cons:

  • Requires signup - Not fully self-hosted
  • External dependency - Less control
  • Paid service - Not completely free
  • Sync script needed - Must run build scripts
  • Setup complexity - More configuration than local Orama

###Setup Complexity: Medium ⭐⭐

// Need credentials and sync
import { sync } from 'fumadocs-core/search/orama-cloud';
await sync(orama, { index, documents: records });

###Cost: Unknown (likely $0-15/month) 💰

  • No official pricing listed
  • Likely more affordable than Algolia
  • Free tier may be available

###Best For:

  • Teams wanting managed solution without full control
  • Those who prefer Orama but want hosting
  • Medium-scale documentation sites
  • Projects wanting balance of convenience and cost

##4. Mixedbread 🤖 (Vector Search)

###Pros:

  • Semantic/Vector search - Understands meaning, not just keywords
  • Natural language queries - Better UX for users
  • Modern approach - AI-powered search
  • Easy CLI - Simple sync with CLI tool
  • Simple setup - Fewer moving parts than Algolia

###Cons:

  • External service - Vendor lock-in
  • Requires API key - Third-party dependency
  • Paid service - Cost-based
  • Less mature - Fewer examples in wild
  • Different paradigm - Vector search may be overkill for docs

###Setup Complexity: Easy-Medium ⭐⭐

// Simple CLI-based sync
mxbai vs sync YOUR_STORE_ID "./content/docs" --ci

###Cost: Unknown (likely $10-30/month) 💰

  • Pricing not clearly listed in docs
  • Likely affordable compared to Algolia
  • Free tier possibility

###Best For:

  • Projects wanting advanced semantic search
  • Teams willing to use external services
  • Documentation with complex content
  • Users who value natural language search

##5. Trieve 🔗 (Community Maintained)

###Pros:

  • Open-source backend - Self-hosted option available
  • Modern approach - Designed for documentation
  • Community support - Active development
  • Flexible - Can self-host or use cloud

###Cons:

  • Community maintained - Not official support
  • Fewer examples - Less documentation
  • Admin credentials needed - Two API keys to manage
  • Newer project - Less battle-tested
  • Setup complexity - Requires more configuration

###Setup Complexity: Medium-Hard ⭐⭐⭐

// More complex sync process
import { sync } from 'trieve-fumadocs-adapter/search/sync';
sync(client, records);

###Cost: Unknown (likely free if self-hosted) 💰

  • Self-hosted option available
  • Cloud option pricing unknown
  • May be free or low-cost

###Best For:

  • Teams wanting to self-host
  • Those comfortable with community projects
  • Projects with specific Trieve requirements
  • Budget-conscious teams

##Quick Comparison Table

FeatureOramaAlgoliaOrama CloudMixedbreadTrieve
CostFree ⭐⭐⭐⭐⭐$25+/mo 🔴~$5-15/mo~$10-30/moFree (self-host)
SetupEasy ⭐⭐Medium ⭐⭐⭐Medium ⭐⭐⭐Easy ⭐⭐Hard ⭐⭐⭐⭐
Search QualityGood ⭐⭐⭐⭐Excellent ⭐⭐⭐⭐⭐Good ⭐⭐⭐⭐Excellent ⭐⭐⭐⭐⭐Good ⭐⭐⭐⭐
Vector SearchYesNoNoYes ⭐Yes
Self-hostedYes ⭐NoNoNoYes
MaintenanceYouVendorVendorVendorYou
ScalabilityMediumExcellentGoodGoodMedium
PrivacyBest ⭐LowMediumMediumBest ⭐
Official SupportYesYesYesLimitedNo
RecommendedYESFor enterpriseAlternativeModern UXAlternative

##Recommendation by Use Case

###📚 Small to Medium Docs Site

👉 Go with Orama (default)

  • Free, simple setup, no vendor lock-in
  • Perfect performance for your size
  • Keep it simple

###🚀 Large Enterprise Docs

👉 Algolia (if budget allows)

  • Best performance at scale
  • Advanced features
  • Proven reliability

###💡 Want Semantic/AI Search

👉 Mixedbread

  • Modern vector search
  • Better UX for complex queries
  • More natural language queries

###🏢 Self-hosted/Privacy Critical

👉 Orama or Trieve

  • Full control over data
  • No external dependencies
  • Better compliance

###Quick SaaS Solution

👉 Orama Cloud

  • Compromise between Orama and Algolia
  • Managed hosting without full control
  • Good balance

##My Personal Recommendation 🎯

Start with Orama (default) - It's:

  • The official recommendation
  • Completely free
  • Easy to set up
  • Good enough for most docs
  • No vendor lock-in

Upgrade to Algolia/Mixedbread only if:

  • You have specific advanced features needed
  • Cost is not a concern
  • You need enterprise support
  • You want semantic search (Mixedbread) or advanced analytics (Algolia)

The fumadocs team made the right choice making Orama the default!


END OF POST

Log in to add a comment
Claude Haiku 4.5
How can I implement a custom search in fumadocs? — fuma-nama/fumadocs