fuse.js, fuzzy, fuzzy-search, and fuzzyset are JavaScript libraries designed to implement fuzzy string matching in browser or Node.js environments. They help developers build search features that tolerate typos, partial matches, and varied input formats by calculating similarity between query strings and a dataset. Each library uses different algorithms and data structures under the hood, leading to trade-offs in performance, memory usage, configurability, and ease of integration.
When building UIs with search—like type-ahead inputs, filtering dashboards, or command menus—you often can’t rely on exact string matches. Users make typos, abbreviate terms, or expect results from partial input. That’s where fuzzy search libraries come in. But not all are created equal. Let’s break down how fuse.js, fuzzy, fuzzy-search, and fuzzyset differ in real-world usage.
fuse.js uses the Bitap algorithm (a variation of the Levenshtein distance approach) with enhancements for speed and relevance. It scores matches based on character proximity, sequence order, and location within the string. You get ranked results with match positions highlighted.
// fuse.js example
const fuse = new Fuse(['apple', 'banana', 'cherry'], {
includeScore: true,
threshold: 0.3 // lower = stricter
});
console.log(fuse.search('bana'));
// → [{ item: 'banana', score: 0.125 }]
fuzzy implements a simpler pattern-matching heuristic: it checks if characters from the query appear in order in the target string, assigning a score based on gaps and case sensitivity. No edit distance—just subsequence alignment.
// fuzzy example
import { filter } from 'fuzzy';
const results = filter('bna', ['apple', 'banana', 'cherry']);
console.log(results[0].string); // 'banana'
fuzzy-search also uses a subsequence-based approach, similar to fuzzy, but adds basic support for searching within object properties. It doesn’t compute detailed scores—just returns matches above a hardcoded similarity bar.
// fuzzy-search example
const searcher = new FuzzySearch(['apple', 'banana'], null, {
caseSensitive: false
});
console.log(searcher.search('bana')); // ['banana']
fuzzyset takes a different path: it precomputes similarity hashes using n-grams and stores them in a lookup structure. At query time, it finds candidates with overlapping n-grams and falls back to exact matches if nothing is close enough. This works well for static dictionaries but struggles with dynamic data.
// fuzzyset example
const fz = new FuzzySet();
fz.add('banana');
console.log(fz.get('bana')); // [[0.8, 'banana']]
Only fuse.js handles nested objects gracefully out of the box:
const books = [
{ title: 'The Great Gatsby', author: { name: 'F. Scott Fitzgerald' } }
];
const fuse = new Fuse(books, { keys: ['title', 'author.name'] });
fuse.search('fitzgerald'); // matches author.name
fuzzy-search supports flat objects via a keys option, but not nesting:
// fuzzy-search with flat objects
const users = [{ name: 'Alice', email: 'alice@example.com' }];
const searcher = new FuzzySearch(users, ['name', 'email']);
fuzzy and fuzzyset work only with strings. To search objects, you must extract or stringify values yourself.
fuse.js gives you deep control:
threshold: how “fuzzy” to allow (0 = exact, 1 = anything)distance: how far apart matching characters can bekeys: which fields to search, with optional weightsincludeMatches: get character-level match positionsThis makes it possible to fine-tune for domain-specific needs (e.g., prioritize SKU codes over product names).
fuzzy and fuzzy-search offer minimal knobs—mostly just case sensitivity. You can’t adjust match strictness or field importance.
fuzzyset has almost no runtime configuration. Once built, the index is fixed.
fuse.js supports .add(), .remove(), and .setCollection() for live updates—critical for apps where data changes after initial load (e.g., chat message filters).
fuzzy and fuzzy-search require rebuilding the entire matcher when data changes, which is fine for small sets but costly at scale.
fuzzyset allows .add() but not removal or updates. If your dataset mutates, you’ll need to recreate the whole structure.
fuse.js handles Unicode reasonably well and supports accent folding via plugins. It’s tested across languages.
fuzzy and fuzzy-search work with Unicode strings but don’t normalize accents or diacritics—so “café” won’t match “cafe” without preprocessing.
fuzzyset has known issues with non-ASCII characters and may produce inconsistent results with emojis or CJK text.
fuse.js is actively maintained, ships with TypeScript definitions, supports ES modules, and works seamlessly in bundlers like Vite or Webpack.
fuzzy is stable but rarely updated. It’s tiny (~2KB) and dependency-free—good for constrained environments.
fuzzy-search hasn’t had significant updates since 2019. It works but lacks modern tooling support.
fuzzyset is effectively deprecated. The last meaningful commit was in 2016, and it fails in strict CSP environments due to eval() usage. Do not use it in new projects.
| Scenario | Recommended Library |
|---|---|
| Complex object search with weighting | fuse.js |
| Simple command palette (<50 items) | fuzzy |
| Flat object filtering, moderate size | fuzzy-search |
| Static dictionary with precomputed lookups | ❌ Avoid fuzzyset; use fuse.js instead |
For most professional frontend applications, fuse.js is the clear choice. It balances power, flexibility, and reliability without bloating your bundle. Reserve fuzzy for micro-interactions where every byte counts. Treat fuzzy-search as a legacy option if already in use—but migrate to Fuse.js for new work. And leave fuzzyset in the past; its design doesn’t hold up in modern web apps.
Choose fuse.js when you need a well-maintained, flexible, and feature-rich fuzzy search solution with strong defaults and fine-grained control over matching behavior. It supports nested object searching, weighted fields, and custom scoring, making it ideal for complex datasets like product catalogs or user directories. Its active maintenance and comprehensive documentation reduce long-term risk in production applications.
Choose fuzzy if you're working on a lightweight project where simplicity and minimal bundle size matter more than advanced features. It provides basic fuzzy matching using a simple pattern-scoring algorithm and is best suited for small lists (e.g., command palettes or autocomplete with fewer than 100 items). However, it lacks support for objects, weights, or threshold tuning, limiting its use in data-rich contexts.
Choose fuzzy-search when you need straightforward fuzzy matching over arrays of strings or flat objects without complex configuration. It’s easy to integrate and performs adequately for medium-sized datasets, but offers fewer customization options than Fuse.js. Avoid it if you require nested property traversal, relevance scoring, or dynamic reindexing.
Choose fuzzyset only for very specific use cases involving precomputed similarity lookups with exact match fallbacks. It builds an internal trie-like structure optimized for repeated queries against a static dataset. However, it hasn’t seen meaningful updates in years, lacks modern TypeScript support, and has known limitations with Unicode and non-English text. Do not use it in new projects unless you’ve validated its behavior against your exact data shape.
Through contributions, donations, and sponsorship, you allow Fuse.js to thrive. Also, you will be recognized as a beacon of support to open-source developers.
|
|
|
|
Fuse.js is a lightweight fuzzy-search, in JavaScript, with zero dependencies.
Fuse.js supports all browsers that are ES5-compliant (IE8 and below are not supported).
To check out a live demo and docs, visit fusejs.io.
Here's a separate document for developers.
We've set up a separate document for our contribution guidelines.