Building Search Solutions: From MeiliSearch to Static Fuse.js

search
documentation
python
javascript
sphinx
ansys
My journey developing search solutions for documentation - from Python scrapers with MeiliSearch to static search with Fuse.js
Author

Revathy Venugopal

Published

September 21, 2025

Introduction

One of the most challenging aspects of maintaining technical documentation is making content discoverable. Over the past few years, I’ve developed various search solutions for documentation sites. This journey took me from sophisticated backend solutions with MeiliSearch to elegant static search implementations with Fuse.js. Here’s the story of why I made this transition and the lessons learned along the way.

The Beginning: MeiliSearch Implementation

Why MeiliSearch?

When I first started working on search functionality for documentation sites, MeiliSearch seemed like the perfect solution:

  • Lightning Fast: Sub-millisecond search results
  • Typo Tolerance: Built-in fuzzy matching
  • Easy Integration: Simple REST API
  • Rich Features: Faceted search, filtering, highlighting

Building the Python Scraper and Indexer

My first implementation involved a comprehensive Python-based solution that could:

  • Scrape Documentation Sites: Recursively crawl through documentation pages
  • Extract Content: Parse HTML and extract meaningful text and metadata (Small improvements using pymeilisearch-scraper)
  • Index Content: Create searchable indexes with proper weighting and faceting (slight improvements using pymeilisearch)
  • Manage Multi-Version: Handle different versions of the same documentation

The system included sophisticated features like:

  • Asynchronous scraping for performance
  • Content deduplication and cleaning
  • Section-based indexing for better relevance
  • Automatic link discovery and following
  • Metadata extraction and enrichment

Frontend Integration

The frontend implementation provided a rich search experience with features like:

  • Real-time Search: Instant results as users type
  • Debounced Input: Optimized API calls to prevent overloading
  • Highlighted Results: Search terms highlighted in results
  • Keyboard Navigation: Arrow keys and Enter support
  • Responsive Design: Works on all devices
  • Error Handling: Graceful fallbacks when search is unavailable
  • Multi library Support: Compatible with jQuery, vanilla JS, and modern frameworks

The interface included sophisticated features like result ranking, multisearch dropdowns, and advanced navigation.

The Challenges: Why MeiliSearch Wasn’t Enough

1. Private Documentation Projects

The biggest challenge came when working with private documentation.

Issues with Private Documentation:

  • Authentication: Many documentation sites required login, making scraping difficult
  • Access Restrictions: VPNs and firewalls blocked external scrapers
  • Rate Limiting: Frequent requests led to IP bans

Each private project required custom authentication handling, making the scraper increasingly complex and fragile.

2. Multi-Version Documentation Nightmare

The complexity multiplied with multi-version documentation. Managing multiple versions (latest, v2.1, v2.0, v1.9, dev) created exponential complexity:

Multi-Version Challenges:

  • Storage Explosion: Linear growth with versions (5 versions × 1000 pages = 5000 documents)
  • Search Complexity: Each index had to be version-aware
  • Maintenance Overhead: Constant re-indexing required for every release
  • Indexing Delays: Large indexes took time to build and update
  • Database Corruption Risks: More frequent updates increased chances of index corruption

Each new version essentially doubled the maintenance effort while making the search experience more confusing for users.

The Solution: Static Search with Fuse.js

After experiencing these challenges, I shifted to a static search approach using Fuse.js:

1. Build-Time Index Generation

Instead of runtime scraping, I created build-time index generation using a Sphinx extension that:

  • Processes Documents During Build: Extracts content directly from the documentation source
  • Generates Clean Text: Removes navigation, sidebars, and non-content elements
  • Creates Structured Index: Organizes content by sections, headings, and metadata
  • Optimizes for Performance: Limits content length and removes excessive whitespace
  • Version-Specific Indexes: Each documentation version gets its own focused index

This approach eliminates all the authentication and access issues since the indexing happens during the documentation build process, which already has access to all content.

2. Fuse.js Integration

The frontend implementation with Fuse.js provides excellent search without a backend. The implementation includes:

Core Features:

  • Fuzzy Search: Handles typos and partial matches intelligently
  • Weighted Scoring: Prioritizes title matches over content matches
  • Real-time Results: Instant search as users type
  • Keyboard Navigation: Full keyboard support for accessibility
  • Highlight Matching: Visual highlighting of search terms in results
  • Performance Optimized: Debounced input and efficient algorithms

Advanced Capabilities:

  • Relevance Scoring: Shows match confidence percentages
  • Section-Aware Search: Can search within specific document sections
  • Snippet Extraction: Intelligent excerpt generation around matches
  • Multi-field Search: Searches titles, content, and metadata simultaneously
  • No Network Dependencies: Completely client-side after initial load

The system provides a search experience that rivals server-based solutions while being completely self-contained.

3. Beautiful and Responsive Design

The search interface includes comprehensive styling that provides:

Visual Design:

  • Modern Search Box: Rounded corners, subtle shadows, and smooth focus transitions
  • Dropdown Results: Clean card-based layout with proper spacing and typography
  • Syntax Highlighting: Color-coded search term highlighting in results
  • Responsive Design: Adapts perfectly to mobile and desktop screens
  • Dark Mode Support: Automatic theme switching based on user preferences

User Experience:

  • Accessibility: Full keyboard navigation and screen reader support
  • Performance Indicators: Shows relevance scores and result counts
  • Visual Feedback: Hover effects and selection states
  • Loading States: Graceful handling of loading and error conditions
  • Print Support: Clean printing without search interface elements

The styling ensures the search experience feels native to any documentation theme while maintaining excellent usability across all devices.

Lessons Learned

1. Complexity Doesn’t Always Mean Better

MeiliSearch offered advanced features, but the operational overhead wasn’t justified for most documentation sites.

2. Static Solutions Scale Better

As the number of projects grew, managing multiple MeiliSearch instances became unwieldy. Static search scales linearly with zero additional infrastructure.

3. Build-Time vs Runtime Processing

Processing content during documentation build is more reliable than runtime scraping, especially for private or complex sites.

4. User Experience Matters More Than Technology

Fuse.js provides an excellent search experience that users don’t distinguish from server-based solutions.

5. Maintenance Burden Is Real

The ongoing maintenance of servers, security updates, and monitoring was a significant hidden cost that static solutions eliminate.

Conclusion

The journey from MeiliSearch to Fuse.js taught me that the most sophisticated solution isn’t always the best solution. For documentation search, static generation with client-side search provides:

  • Better reliability (no servers to fail)
  • Lower costs (no infrastructure)
  • Easier maintenance (build-time generation)
  • Better security (no external dependencies)
  • Universal compatibility (works everywhere)