Migrating from fuzzysort to rapid-fuzzy
fuzzysort is a fast fuzzy search library written in pure JavaScript. Like rapid-fuzzy, it matches a query when its characters occur in the item in order, and ranks matches with its own scoring. rapid-fuzzy uses the nucleo matcher (the engine of the Helix editor) in a Rust core, and adds query syntax, weighted object search, distance functions and batch APIs. Scores and rankings differ between the two.
Installation
Section titled “Installation”# Remove fuzzysortnpm uninstall fuzzysort
# Install rapid-fuzzynpm install rapid-fuzzyQuick Start
Section titled “Quick Start”// Before (fuzzysort)import fuzzysort from 'fuzzysort';const results = fuzzysort.go('typscript', ['TypeScript', 'JavaScript', 'Python']);console.log(results[0].target); // 'TypeScript'
// After (rapid-fuzzy)import { search } from 'rapid-fuzzy';const results = search('typscript', ['TypeScript', 'JavaScript', 'Python']);console.log(results[0].item); // 'TypeScript'API Mapping
Section titled “API Mapping”| fuzzysort | rapid-fuzzy | Notes |
|---|---|---|
fuzzysort.go(query, targets) |
search(query, items) |
No constructor needed |
fuzzysort.go(query, targets, { key }) |
searchObjects(query, items, { keys }) |
See Object Search |
result.highlight('<b>', '</b>') |
highlight(item, positions, '<b>', '</b>') |
Built-in highlight utility |
fuzzysort.prepare(target) |
new FuzzyIndex(items) |
Persistent index, mutable |
result.target |
result.item |
Different property name |
result.score |
result.score |
Different scale (see below) |
result.indexes |
result.positions |
Character indices |
options.threshold |
{ minScore } |
Same direction, different scores (see below) |
options.limit |
{ maxResults } or pass a number |
search(q, items, 5) |
options.key / options.keys |
searchObjects(q, items, { keys }) |
See Object Search |
Score Direction
Section titled “Score Direction”Important: fuzzysort and rapid-fuzzy use different scoring systems. Both use 0–1 with higher = better, but the same match gets different scores (tsc → TypeScript: 0.74 in fuzzysort, 0.83 in rapid-fuzzy), so pick minScore from rapid-fuzzy’s scores on your data:
| fuzzysort | rapid-fuzzy | |
|---|---|---|
| Perfect match | 1 |
1.0 |
| No match | not returned | not returned |
| Scale | 0–1 (higher = better) | 0.0–1.0 (higher = better) |
| Default threshold | 0.5 (fuzzysort 4; 0 in 3.x) |
None (include all) |
// fuzzysort 4: threshold is 0-1, higher = stricter, and defaults to 0.5fuzzysort.go('query', items, { threshold: 0.3 });
// rapid-fuzzy: minScore is 0-1, higher = stricter, and defaults to 0 (include all)search('query', items, { minScore: 0.3 });Common Patterns
Section titled “Common Patterns”Basic search
Section titled “Basic search”// fuzzysortconst results = fuzzysort.go('query', items);results[0].target; // matched stringresults[0].score; // 0–1
// rapid-fuzzyconst results = search('query', items);results[0].item; // matched stringresults[0].score; // 0.0–1.0Limiting results
Section titled “Limiting results”// fuzzysortconst results = fuzzysort.go('query', items, { limit: 5 });
// rapid-fuzzy — either form worksconst results = search('query', items, 5);const results = search('query', items, { maxResults: 5 });Score threshold
Section titled “Score threshold”// fuzzysort — threshold is 0-1 (default 0.5 since fuzzysort 4)fuzzysort.go('query', items, { threshold: 0.5 });
// rapid-fuzzy — minScore is 0-1 where higher = strictersearch('query', items, { minScore: 0.5 });Object search
Section titled “Object search”// fuzzysort — single keyfuzzysort.go('john', users, { key: 'name' });
// fuzzysort — multiple keysfuzzysort.go('john', users, { keys: ['name', 'email'] });
// rapid-fuzzyimport { searchObjects } from 'rapid-fuzzy';searchObjects('john', users, { keys: ['name', 'email'],});
// rapid-fuzzy — weighted keyssearchObjects('john', users, { keys: [ { name: 'name', weight: 2.0 }, { name: 'email', weight: 1.0 }, ],});Match highlighting
Section titled “Match highlighting”// fuzzysort — built-in HTML highlightconst [result] = fuzzysort.go('tsc', ['TypeScript']);result.highlight('<b>', '</b>'); // '<b>T</b>ype<b>Sc</b>ript'
// rapid-fuzzy — highlight utility with positionsimport { search, highlight } from 'rapid-fuzzy';const results = search('query', items, { includePositions: true });highlight(results[0].item, results[0].positions, '<b>', '</b>');
// Callback form (React, JSX)highlight(results[0].item, results[0].positions, (matched) => `<mark>${matched}</mark>`);Prepared targets / persistent index
Section titled “Prepared targets / persistent index”// fuzzysort — prepare targets for faster repeated searchesconst prepared = items.map(fuzzysort.prepare);fuzzysort.go('query', prepared);
// rapid-fuzzy — persistent index with mutation supportimport { FuzzyIndex } from 'rapid-fuzzy';const index = new FuzzyIndex(items);index.search('query');
// Mutate without rebuildingindex.add('new item');index.remove(2); // swap-remove by index
// Free Rust-side memory when doneindex.destroy();Performance
Section titled “Performance”From the benchmarks (Node.js 22, Linux x64, Intel Xeon @ 2.10GHz, 4 vCPUs; ops/s, higher is better; fuzzysort with prepared targets from 1K items on):
| Dataset size | rapid-fuzzy search() |
FuzzyIndex |
fuzzysort |
|---|---|---|---|
| Small (20 items) | 157,995 ops/s | 208,250 ops/s | 1,271,223 ops/s |
| Medium (1K items) | 3,502 ops/s | 50,318 ops/s | 54,110 ops/s |
| Large (10K items) | 508 ops/s | 4,803 ops/s | 2,977 ops/s |
| Large (10K items, rotating queries) | 451 ops/s | 4,644 ops/s | 2,231 ops/s |
| Huge (100K items) | — | 1,125 ops/s | 231 ops/s |
fuzzysort was about 6x faster on 20 items and about as fast on 1K items. FuzzyIndex was 1.6-2.1x faster on 10K items, and about 5x faster on 100K items, where it scored candidates on 4 threads (about 2x faster on one thread). Standalone search() was slower than fuzzysort’s prepared search at every size, because it converts every item on each call.
Why Choose rapid-fuzzy Over fuzzysort?
Section titled “Why Choose rapid-fuzzy Over fuzzysort?”fuzzysort is an excellent choice for small and medium lists in the browser, with no native addon or WebAssembly module to load. rapid-fuzzy is worth it when you need:
- Distance functions: Levenshtein, Damerau-Levenshtein, Hamming, Indel, Jaro, Jaro-Winkler, Sorensen-Dice, and token-based ratios — useful beyond search
- Query syntax: Exclude (
!term), prefix (^term), suffix (term$), exact ('term) operators - Batch APIs:
levenshteinBatch,jaroWinklerMany, etc. for bulk operations - Object search with weighted keys:
searchObjects()andFuzzyObjectIndexwith per-key weights - Mutable persistent index:
FuzzyIndexsupportsadd()/remove()without rebuilding, andserialize()/deserialize() - Large lists in Node.js: native code that scales to 100K+ items
Additional Capabilities
Section titled “Additional Capabilities”rapid-fuzzy includes distance/similarity functions that fuzzysort does not offer:
import { levenshtein, // edit distance normalizedLevenshtein, // 0-1 similarity jaroWinkler, // name matching sorensenDice, // text similarity damerauLevenshtein, // transposition-aware} from 'rapid-fuzzy';
// Batch APIs for bulk operationsimport { levenshteinBatch, jaroWinklerMany } from 'rapid-fuzzy';