A curated list of the absolute fastest fuzzy search libraries for JavaScript in the browser. Whether you need an ultra-lightweight filter, SublimeText-like search as you type, or WebAssembly-powered speed for massive datasets, this list covers the best options available.
| Library | Bundle Size | Approach | Best For | Stars |
|---|---|---|---|---|
| uFuzzy | ~3KB | Multi-phase filtering | Maximum speed, autocomplete | 3k |
| fuzzysort | ~7KB | SublimeText scoring | Search-as-you-type | 28M+ downloads |
| FlexSearch | ~10KB | Contextual index | Large full-text search | 13.8k |
| MiniSearch | ~12KB | Inverted index | Full-text with features | 6k |
| FZF for JS | ~8KB | fzf algorithm | Command palettes | 2M+ weekly |
| Fuse.js | ~25KB | Bitap + index | Battle-tested fuzzy | 28k+ stars |
| fast-fuzzy | ~5KB | Sellers + Damerau-Levenshtein | Fast Levenshtein matching | 1.3M+ downloads |
| Orama | ~2KB | BM25 + vector | Hybrid search (keyword + semantic) | Active |
| microfuzzy | ~2KB | Simple filter | Tiny bundle, simple lists | 1.4M+ downloads |
| Lunr.js | ~8KB | Solr-like inverted index | Static site docs | Classic |
| FlashFuzzy | WASM | Bitap + Bloom filter | 100K+ records | New |
| nucleo-matcher-wasm | WASM | Smith-Waterman | Editor-quality matching | Helix-backed |
| rapid-fuzzy | WASM | Rust-powered | 15,000x faster than Fuse | New |
| USearch | WASM | SIMD-optimized | Vector + text search | 4.2k |
These libraries are written in JavaScript/TypeScript and are optimized for fast client-side searching.
1. uFuzzy
- Focus: Maximum speed and efficiency with high-quality matching.
- Why it's awesome: Often cited as the fastest JS fuzzy matcher. It employs a multi-phase strategy (filtering, scoring, sorting) to handle large datasets instantly. It is tiny and extremely performant.
- Best for: Scenarios where performance is the absolute highest priority and you want precise, fast filtering.
2. fuzzysort
- Focus: Speed and "SublimeText-like" fuzzy search.
- Why it's awesome: Extremely fast and heavily optimized for the specific use case of search-as-you-type filtering (like command palettes or dropdowns). Single-purpose, zero-config.
- Best for: Narrow, list-based filtering where users expect instantaneous feedback as they type.
3. FlexSearch
- Focus: Maximum raw throughput for full-text search.
- Why it's awesome: Benchmarks show it performing queries up to 1,000,000x faster than competing libraries. Uses a "contextual index" scoring algorithm based on a pre-scored lexical dictionary. Supports Web Workers, persistent indexes (IndexedDB, Redis, SQLite, Postgres), and multi-language (CJK, Arabic, Cyrillic).
- Best for: Large-document full-text search where raw query speed is the top priority.
4. MiniSearch
- Focus: Feature-rich, in-memory full-text search.
- Why it's awesome: While slightly heavier than uFuzzy, it offers a great balance of speed and professional search features (like field boosting, exact match vs. fuzzy match, and prefix matching).
- Best for: Documentation, static sites, or complex client-side search requirements.
- Focus: Port of the legendary CLI
fzfalgorithm to the browser. - Why it's awesome: Brings the exact same scoring and ranking system from the command-line fzf into JavaScript. Supports case sensitivity, tiebreakers, async finder, and backward matching. 2M+ weekly downloads on npm.
- Best for: Command palettes, file finders, and any UI that needs fzf-quality matching.
6. Fuse.js
- Focus: Feature-complete, robust industry standard.
- Why it's awesome: While not always the top in raw speed benchmarks for massive datasets, it supports Web Workers (
FuseWorker), allowing you to offload the search to a background thread to prevent UI freezing. Latest v7.x adds token search, extended search, and logical queries. - Best for: Applications requiring a battle-tested library with complex configuration and good performance.
7. fast-fuzzy
- Focus: Fast Damerau-Levenshtein distance with Sellers substring matching.
- Why it's awesome: Uses a modified Levenshtein algorithm (Peter Sellers' method) with Damerau-Levenshtein by default (transposition-friendly). Internally builds a Trie with subtree pruning — skips entire branches that can't possibly score above threshold. Scores 0-1 with excellent normalization (unicode, symbols, whitespace, graphemes).
- Best for: When you need Levenshtein-style edit distance with substring matching and good Unicode support. 1.3M+ weekly downloads.
8. Orama
- Focus: Full-text, vector, and hybrid search in one tiny library (<2KB).
- Why it's awesome: Zero-dependency TypeScript search engine with typo tolerance, BM25 ranking, facets, filters, geosearch, and an Answer Engine (RAG) API. Runs in browser, server, or edge. Actively maintained by a dedicated team.
- Best for: Modern web apps that need both keyword and semantic/vector search without external infrastructure.
9. microfuzzy
- Focus: Tiny bundle size (2KB gzipped) and simplicity.
- Why it's awesome: When you don't need the complexity of Levenshtein distances and just want a simple, blazing-fast array filter, microfuzz does the job without bloating your bundle.
- Best for: Simple UI components where bundle size matters as much as speed.
10. Lunr.js
- Focus: Server-like full-text search on the client.
- Why it's awesome: A classic in the space — inspired by Solr, but running entirely in the browser. Supports field-scoped search, boosting, and pre-built indexes. Well-documented with a mature API.
- Best for: Static site documentation search and traditional full-text use cases.
11. fuzziersort
- Focus: Improved SublimeText-like fuzzy search, fork of fuzzysort.
- Why it's awesome: An actively maintained fork of fuzzysort with bug fixes, improved scoring, and better TypeScript support. Drop-in replacement if fuzzysort's last update (2 years ago) concerns you.
- Best for: Projects that want fuzzysort's approach with more recent maintenance.
- Focus: Fast, accurate, and multilingual fuzzy search.
- Why it's awesome: Built specifically for multilingual accuracy — handles accented characters, CJK, and complex Unicode properly. Uses a custom scoring algorithm optimized for real-world text.
- Best for: International applications where multilingual accuracy matters.
13. List.js
- Focus: Search, sort, and filter for existing HTML lists/tables.
- Why it's awesome: Drop-in library that adds fuzzy search to existing HTML elements without rewriting your markup. 11.2k stars. Handles pagination, sorting, and filtering together.
- Best for: Adding search to existing tables, lists, or directories without a framework rewrite.
- Focus: Lightweight fuzzy search from the LVCE (formerly Tabby) editor project.
- Why it's awesome: Minimal, dependency-free fuzzy search implementation from a real editor project. Actively maintained with recent updates.
- Best for: Editor-like UIs and minimal dependency requirements.
For datasets that are simply too large for JavaScript's V8 engine to iterate over quickly, we can bring system-level languages into the browser via WebAssembly.
1. FlashFuzzy (Rust + WASM)
- Why it's awesome: Built in Rust and compiled to WASM. Combines Bloom Filters with the Bitap algorithm to achieve sub-millisecond searches on datasets of 100K+ records. Zero-allocation memory architecture — no GC pauses.
- Status: Available on npm as
flashfuzzy. Live demo available.
2. nucleo-matcher-wasm (Rust + WASM)
- Why it's awesome: Compiles
nucleo-matcher(the same fuzzy matcher used in the Helix editor) to WebAssembly. Claims ~6x faster thanskim's matcher with more faithful Smith-Waterman scoring. Supports fzf-like syntax (^prefix,$postfix,'substring,!negation). - Status: Available on npm as
nucleo-matcher-wasm. Ready for browser use.
3. Fuzzr (Rust + WASM)
- Why it's awesome: Written in Rust, compiled to WASM, using the popular
skimalgorithm. Designed specifically for browser use from the ground up. - Status: Open source on GitHub. Good starting point for Rust->WASM fuzzy search.
4. docfind (Rust + WASM)
- Why it's awesome: A Microsoft-built document search engine combining FST (Finite State Transducers) with FSST compression and RAKE keyword extraction. Sub-millisecond search on 50K+ documents. Index can be embedded directly in the WASM binary for zero network requests. Powers the VS Code documentation site search.
- Status: Production use on code.visualstudio.com. Open source with an interactive live demo.
5. @stll/fuzzy-search-wasm (Rust + WASM)
- Why it's awesome: Approximate substring matching for browsers via WebAssembly. Provides Levenshtein edit distance with same API as
@stll/fuzzy-search. Built withnapi-rs. - Status: Available on npm. Lightweight and focused on the WASM boundary.
6. rapid-fuzzy (Rust + WASM)
- Why it's awesome: Rust-powered fuzzy search and string distance for JavaScript/TypeScript. Claims up to 15,000x faster than Fuse.js in indexed mode.
- Status: Published on npm. Good for high-performance string distance and fuzzy matching.
7. USearch (C++ + WASM)
- Why it's awesome: SIMD-optimized search engine with JavaScript bindings. Supports both vector (ANN) and text fuzzy search. Available in 10+ languages (C++, Python, JS, Rust, Go, etc.). Uses custom SIMD-optimized single-threaded and multi-threaded indexes.
- Status: 4.2k stars. Production-ready with npm packages for browser use.
8. Stork Search (Rust + WASM)
- Why it's awesome: A full-featured static-site search engine compiled to WASM. Index your documents with the Stork CLI, then serve a single
.wasm+.stindex file. TypeScript bindings included. - Status: Mature project with documentation, theming support, and GitHub Actions for CI indexing.
9. Tinysearch (Rust + WASM)
- Why it's awesome: Minimalist WASM-based search engine inspired by Stork, but even simpler. Generates a tiny WASM blob with a built-in index. Ideal for blogs and documentation sites where bundle size matters.
- Status: Lightweight, well-suited for static site generators like Zola and Hugo.
These are primarily server-side search engines that offer WASM builds or client-side JavaScript SDKs, bringing server-grade search into the browser.
1. Meilisearch (Rust)
- Why it's awesome: 58.6k stars. Lightning-fast search engine with typo tolerance, faceting, filtering, and geosearch. Offers a browser-compatible WASM client via
meilisearch-jsthat can work with an embedded search index. Supports hybrid search (keyword + vector/semantic). - Browser path: Use the JS client, or embed the index via WASM for offline-first search.
2. Typesense (C++)
- Why it's awesome: 26.3k stars. Open-source alternative to Algolia with typo tolerance, synonyms, geosearch, and vector search. Offers
typesense-jsclient SDK andtypesense-instantsearch-adapterfor Algolia InstantSearch compatibility. - Browser path: Use the JS client against a Typesense server, or embed via WASM for self-contained search.
3. Tantivy (Rust)
- Why it's awesome: A Rust full-text search library similar to Lucene. Can be compiled to WASM via
wasm-pack. Extremely fast inverted index with BM25 ranking, tokenizer pipeline, and segment-based architecture. - Browser path: Compile to WASM for a full Lucene-grade search engine in the browser. See tantivy-wasm experiments.
4. SymSpell (C# / multiple ports)
- Why it's awesome: 3.4k stars. Claims 1 million times faster spelling correction and fuzzy search through Symmetric Delete spelling correction algorithm. Available in C#, Java, Python, and JavaScript ports.
- Browser path: Use the JavaScript port directly, or compile the C# version to WASM via Blazor.
If none of the above fit your exact needs, you can compile any of these high-performance fuzzy matchers to WASM yourself.
- nucleo — The fastest Rust fuzzy matcher, used in Helix editor. ~6x faster than
skim. Already has a WASM wrapper to model after. - skim /
fuzzy-matcher— Smith-Waterman based matcher used by theskCLI tool. Well-documentedSkimMatcherV2API. - bitap — Pure Rust Bitap algorithm implementation. Compiles cleanly to WASM with no-std support.
- flash-fuzzy-core — The core Bitap + Bloom filter engine behind FlashFuzzy. Zero dependencies,
no_stdcompatible. - fuzzy-matcher — The core matching algorithm used by skim. Supports multiple scoring strategies (Smith-Waterman, Skim, consecutive bonus).
- fzy — A fast, simple fuzzy text selector. The C implementation is compact and compiles easily to WASM. The algorithm is used by many editors and tools.
- lib_fts — Forrest Smith's reverse-engineered Sublime Text fuzzy matching algorithm in C++. The original reference implementation for many JS ports.
- Teg — A fast fuzzy finder written in C with an emphasis on simplicity.
- fzf — The original CLI fuzzy finder written in Go. While primarily Go, C bindings exist and it compiles to WASM via various toolchains. The scoring algorithm is the gold standard for command-palette UX.
- fzf — The original CLI fuzzy finder written in Go. Can be compiled to WASM via TinyGo, though the JS port (fzf-for-js) is usually more practical.
- skim — A fuzzy finder in Rust (not Go), but worth noting as an alternative fzf implementation with similar WASM potential.
Understanding the core algorithms helps pick the right library:
| Algorithm | Used By | Strengths | Weaknesses |
|---|---|---|---|
| Levenshtein Distance | fast-fuzzy, FlashFuzzy | Edit distance, intuitive | Slow on large datasets |
| Damerau-Levenshtein | fast-fuzzy | Handles transpositions | Still O(n*m) |
| Bitap (Shift-OR) | FlashFuzzy, Fuse.js | Fast substring, bit-parallel | Limited edit distance |
| Smith-Waterman | nucleo, skim | Local alignment, accurate | Computationally expensive |
| BM25 | Orama, Tantivy | Ranking relevance, industry standard | Requires inverted index |
| SublimeText Scoring | fuzzysort, fuzziersort | Great UX for search-as-you-type | Heuristic, not edit-distance |
| Sellers' Method | fast-fuzzy | Fast substring with edit distance | Niche algorithm |
| FST (Finite State Transducer) | docfind | Sub-ms lookup, compressed index | Complex to build |
| Symmetric Delete | SymSpell | 1Mx faster spelling correction | Pre-computation required |
All benchmarks run on Bun 24.3.0 (Linux x64) for JS and Zig 0.16.0 ReleaseFast for native. Each algorithm scores every candidate in the corpus against queries (exact + typos + partial). QPS = queries per second (higher is better). q = average match quality (0..1, higher is better).
Direct comparison of the same algorithm implemented in both Zig (ReleaseFast native) and JavaScript. Measures raw compute performance without WASM overhead.
| Algorithm | JS QPS (50 items) | Zig QPS (50 items) | Speedup | JS QPS (425 items) | Zig QPS (425 items) | Speedup |
|---|---|---|---|---|---|---|
| SublimeScore | 11.6K | 45.5K | 3.9x | 3.4K | 4.9K | 1.4x |
| Dice (2-gram) | 3.5K | 20.3K | 5.8x | 616 | 3.2K | 5.2x |
| LCS Ratio | 5.9K | 14.8K | 2.5x | 2.3K | 2.1K | 0.9x |
| Jaro-Winkler | 6.6K | 12.7K | 1.9x | 2.0K | 2.4K | 1.2x |
| Levenshtein | 4.1K | 5.8K | 1.4x | 1.2K | 2.2K | 1.8x |
| Smith-Waterman | 4.5K | 10.0K | 2.2x | 1.2K | 1.6K | 1.3x |
| Damerau-Lev. | 3.7K | 8.4K | 2.3x | 526 | 1.7K | 3.2x |
| Bitap (k=1) | 341 | 7.4K | 21.7x | 45 | 1.5K | 33x |
Key finding: Zig is 1.4–33x faster than JS for the same algorithms. The biggest wins are on algorithms with heavy inner loops (Bitap: 21-33x, Dice: 5-6x, Damerau: 2-3x). Simpler algorithms (Levenshtein, LCS) show smaller 1.2-2.5x gains. Quality scores are identical — confirming correct porting.
| Algorithm | 50 items | 250 items | 425 items | 330 items | 2180 items |
|---|---|---|---|---|---|
| SublimeScore | 11.6K q/s (q=0.899) | 11.3K q/s (q=0.751) | 3.4K q/s (q=0.760) | 5.5K q/s (q=0.986) | 583 q/s (q=0.889) |
| LCS Ratio | 5.9K q/s (q=0.872) | 4.0K q/s (q=0.882) | 2.3K q/s (q=0.891) | 1.1K q/s (q=0.915) | 283 q/s (q=0.868) |
| Jaro-Winkler | 6.6K q/s (q=0.963) | 4.5K q/s (q=0.951) | 2.0K q/s (q=0.953) | 1.5K q/s (q=0.968) | 277 q/s (q=0.964) |
| Levenshtein | 4.1K q/s (q=0.808) | 3.2K q/s (q=0.800) | 1.2K q/s (q=0.818) | 762 q/s (q=0.862) | 295 q/s (q=0.802) |
| Smith-Waterman | 4.5K q/s (q=0.801) | 2.2K q/s (q=0.805) | 1.2K q/s (q=0.819) | 451 q/s (q=0.861) | 169 q/s (q=0.795) |
| Dice (2-gram) | 3.5K q/s (q=0.788) | 1.7K q/s (q=0.781) | 616 q/s (q=0.791) | 539 q/s (q=0.869) | 111 q/s (q=0.768) |
| Jaccard (2-gram) | 3.3K q/s (q=0.680) | 819 q/s (q=0.693) | 473 q/s (q=0.701) | 259 q/s (q=0.792) | 53 q/s (q=0.655) |
| Damerau-Lev. | 3.7K q/s (q=0.818) | 971 q/s (q=0.827) | 526 q/s (q=0.835) | 174 q/s (q=0.871) | 79 q/s (q=0.818) |
| Bitap (k=1) | 341 q/s (q=0.901) | 86 q/s (q=0.905) | 45 q/s (q=0.924) | 25 q/s (q=0.960) | 5 q/s (q=0.895) |
Same algorithms compiled with Zig ReleaseFast optimization.
| Algorithm | 50 items | 85 items | Speedup vs JS |
|---|---|---|---|
| SublimeScore | 45.5K q/s (q=0.899) | 4.9K q/s (q=0.760) | 1.4–3.9x |
| LCS Ratio | 14.8K q/s (q=0.902) | 2.1K q/s (q=0.891) | 0.9–2.5x |
| Dice (2-gram) | 20.3K q/s (q=0.829) | 3.2K q/s (q=0.791) | 3.2–5.8x |
| Jaro-Winkler | 12.7K q/s (q=0.963) | 2.4K q/s (q=0.953) | 1.2–1.9x |
| Smith-Waterman | 10.0K q/s (q=0.832) | 1.6K q/s (q=0.819) | 1.3–2.2x |
| Damerau-Lev. | 8.4K q/s (q=0.848) | 1.7K q/s (q=0.835) | 1.7–3.2x |
| Levenshtein | 5.8K q/s (q=0.838) | 2.2K q/s (q=0.818) | 1.4–1.8x |
| Library | 50 items | 250 items | 425 items | 330 items | 2180 items |
|---|---|---|---|---|---|
| FlexSearch | 23.9K q/s | 136.5K q/s | 118.4K q/s | 35.5K q/s | 35.4K q/s |
| fuzzysort | 8.5K q/s (q=0.991) | 8.4K q/s (q=0.991) | 8.9K q/s (q=0.991) | 21.5K q/s (q=0.991) | 3.9K q/s (q=0.991) |
| MiniSearch | 3.0K q/s | 24.2K q/s | 13.5K q/s | 15.5K q/s | 6.8K q/s |
| uFuzzy | 3.4K q/s | 5.2K q/s | 4.1K q/s | 3.9K q/s | 1.7K q/s |
| Fuse.js | 1.1K q/s | 721 q/s | 336 q/s | 199 q/s | 68 q/s |
| fast-fuzzy | 390 q/s | 345 q/s | 215 q/s | 231 q/s | 33 q/s |
| Dataset | Fastest Library | Fastest Algo (JS) | Fastest Algo (Zig) | Best Quality |
|---|---|---|---|---|
| 50 cities | FlexSearch (23.9K) | SublimeScore (11.6K) | SublimeScore (45.5K) | Jaro-Winkler (q=0.963) |
| 250 fruits | FlexSearch (136.5K) | SublimeScore (11.3K) | SublimeScore (8.6K) | Jaro-Winkler (q=0.951) |
| 425 tech | FlexSearch (118.4K) | SublimeScore (3.4K) | SublimeScore (4.9K) | Jaro-Winkler (q=0.953) |
| 330 words | FlexSearch (35.5K) | SublimeScore (5.5K) | SublimeScore (5.6K) | SublimeScore (q=0.986) |
| 2180 mixed | FlexSearch (35.4K) | SublimeScore (583) | SublimeScore (590) | Jaro-Winkler (q=0.964) |
-
FlexSearch dominates raw throughput — up to 136K q/s. Its contextual index makes it 10-100x faster than linear-scan libraries.
-
fuzzysort hits the quality sweet spot — 0.991 quality across ALL datasets. Best overall library for search-as-you-type.
-
SublimeScore is the fastest algorithm in both languages — 11.6K q/s in JS, 45.5K q/s in Zig. Best speed/quality tradeoff for custom search engines.
-
Zig gives 1.4–33x speedup over identical JS algorithms. Bitap benefits most (33x — JS BigInt overhead eliminated). Dice (5.8x), Damerau (3.2x), and SublimeScore (3.9x) also see major gains.
-
Jaro-Winkler has the highest quality — consistently 0.95-0.96. Best for name matching and deduplication.
-
Bitap is slow at raw scan (5-341 q/s in JS) but shines with pre-filtering (Bloom filters, inverted indexes) as FlashFuzzy does.
-
For large datasets (>2000 items): FlexSearch (35K q/s) or MiniSearch (6.8K q/s). Libraries with proper indexing scale far better than raw algorithms.
-
Writing hot-path search in Zig and compiling to WASM is a practical way to get near-C performance in the browser. The WASM boundary adds ~2-5x overhead vs native, but the algorithms themselves are still 1.4-33x faster than JS equivalents.
cd benchmarks
bun install
# Run JS benchmarks
bun run bench # full (all algorithms + libraries)
bun run bench --quick # skip huge dataset
bun run bench --lib-only # only test libraries
bun run bench --algo-only # only test algorithms (JS + Zig native)
# Build & run Zig native benchmark
cd zig
zig build -Doptimize=ReleaseFast
./zig-out/bin/fuzzy_benchAll benchmarked algorithms are implemented in Zig (benchmarks/zig/). Currently builds as a native binary for direct JS vs Zig comparison. WASM build is planned once Zig 0.16.0's WASM linker issues are resolved.
| File | Purpose |
|---|---|
benchmarks/zig/src/levenshtein.zig |
Levenshtein distance + score |
benchmarks/zig/src/damerau.zig |
Damerau-Levenshtein with transpositions |
benchmarks/zig/src/bitap.zig |
Bitap (Shift-OR) approximate matching |
benchmarks/zig/src/smith_waterman.zig |
Smith-Waterman local alignment |
benchmarks/zig/src/jaro_winkler.zig |
Jaro-Winkler similarity |
benchmarks/zig/src/ngram.zig |
Dice coefficient + LCS ratio |
benchmarks/zig/src/main.zig |
WASM exports (for future WASM build) |
benchmarks/zig/src/bench.zig |
Native benchmark runner |
benchmarks/zig/build.zig |
Build configuration |
- Zero heap allocation — all algorithms use stack-allocated buffers (512-2048 bytes). No malloc, no GC.
- No std library imports in algorithm files — pure computation only, maximum portability.
- Scores 0..1 — every function returns a normalized score identical to the JS version.
- ReleaseFast optimized — aggressive compiler optimizations for maximum throughput.
cd benchmarks/zig
# Native binary (for benchmarking)
zig build -Doptimize=ReleaseFast
./zig-out/bin/fuzzy_bench
# WASM (when Zig 0.16.0 WASM support stabilizes)
# zig build-lib src/main.zig -target wasm32-wasi -dynamic -O ReleaseFastContributions to this list are welcome!