fuse.js, fuzzy, fuzzy-search, and fuzzyset.js are JavaScript libraries designed to perform approximate string matching directly in the browser or Node.js environment. They allow users to find relevant results even when their input contains typos or does not exactly match the target data. While they share the same goal, they differ significantly in algorithm complexity, configuration options, and intended use cases — ranging from simple list filtering to complex weighted search across nested objects.
When building search features, autocomplete inputs, or data filtering tools in JavaScript, exact string matching is rarely enough. Users make typos, forget spacing, or use partial terms. The fuse.js, fuzzy, fuzzy-search, and fuzzyset.js packages solve this problem by allowing approximate matching. However, they approach the task differently. Let's compare how they handle initialization, configuration, and result ranking.
The way you feed data into these libraries sets the tone for your implementation. Some expect a simple array of strings, while others handle complex objects.
fuse.js accepts an array of strings or objects. It is designed to handle rich data structures out of the box.
import Fuse from 'fuse.js';
const list = [
{ title: "Old Man's War", author: { name: "John Scalzi" } },
{ title: "The Lock Artist", author: { name: "Steve Hamilton" } }
];
const fuse = new Fuse(list, { keys: ['title', 'author.name'] });
fuzzy works primarily with arrays of strings. If you have objects, you must map them to strings first.
import fuzzy from 'fuzzy';
const list = ["John Scalzi", "Steve Hamilton", "Isaac Asimov"];
// No initialization class, just direct function calls
const results = fuzzy.filter("john", list);
fuzzy-search is similar to fuse.js in that it accepts a list of objects and specific keys to search.
import FuzzySearch from 'fuzzy-search';
const list = [
{ name: "John Scalzi", book: "Old Man's War" },
{ name: "Steve Hamilton", book: "The Lock Artist" }
];
const searcher = new FuzzySearch(list, ['name', 'book']);
fuzzyset.js focuses on creating a set of strings to query against. It is optimized for finding the best match from a predefined set.
import FuzzySet from 'fuzzyset.js';
const list = ["John Scalzi", "Steve Hamilton", "Isaac Asimov"];
const set = FuzzySet(list);
// Ready to query immediately
Search relevance is rarely one-size-fits-all. You often need to prioritize certain fields or adjust sensitivity.
fuse.js offers deep configuration. You can assign weights to specific keys and adjust the threshold for what counts as a match.
const fuse = new Fuse(list, {
keys: [
{ name: 'title', weight: 0.8 },
{ name: 'author.name', weight: 0.2 }
],
threshold: 0.4, // 0.0 is exact, 1.0 matches anything
includeScore: true
});
fuzzy has minimal configuration. It relies on the underlying algorithm's defaults. You cannot easily weight specific parts of the string.
// No config object passed during filtering
const results = fuzzy.filter("scalzi", list, {
// Limited options, mostly for pre-processing
pre: (str) => str.toLowerCase()
});
fuzzy-search allows some options during initialization, such as case sensitivity, but lacks the granular weighting of fuse.js.
const searcher = new FuzzySearch(list, ['name'], {
caseSensitive: false,
sort: true
});
fuzzyset.js allows you to adjust the minimum match score when querying. It does not support field weighting since it treats items as single strings.
// Second argument is the minimum match score (0 to 1)
const results = set.get("John Scalzi", 0.5);
// Returns array of [score, string] pairs
Understanding the output format is critical for integrating search results into your UI.
fuse.js returns an array of result objects containing the item, its index, and a relevance score.
const results = fuse.search("scalzi");
// Output: [{ item: {...}, refIndex: 0, score: 0.15 }, ...]
fuzzy returns an array of objects containing the original string, the matched index, and the rendered string with highlights.
const results = fuzzy.filter("john", list);
// Output: [{ string: "John Scalzi", index: 0, matched: [0,1,2,3], ... }]
fuzzy-search returns the original objects from your list that matched the query.
const results = searcher.search("john");
// Output: [{ name: "John Scalzi", book: "Old Man's War" }, ...]
fuzzyset.js returns an array of arrays containing the score and the matched string. You often need to map this to a usable format.
const results = set.get("scalzi");
// Output: [[0.85, "John Scalzi"], [0.4, "Steve Hamilton"]]
Long-term support matters when choosing a dependency for production apps.
fuse.js is actively maintained with regular updates. It has a large community and extensive documentation. It is the safest choice for new projects.
// Importing from modern bundle
import Fuse from 'fuse.js';
fuzzy is stable but sees infrequent updates. It is a "set it and forget it" library that works well for simple tasks but lacks modern features.
// CommonJS or ES module support is standard
import fuzzy from 'fuzzy';
fuzzy-search has seen periods of inactivity. Before using, check the repository for recent commits. It may require forks or patches for modern build tools.
// Verify package health before installing
import FuzzySearch from 'fuzzy-search';
fuzzyset.js is older and primarily maintained for stability. It is not deprecated but is not evolving rapidly. It remains the go-to for Levenshtein-based correction.
// Standard import
import FuzzySet from 'fuzzyset.js';
| Feature | fuse.js | fuzzy | fuzzy-search | fuzzyset.js |
|---|---|---|---|---|
| Best For | Complex search | Simple filtering | Object search | Typo correction |
| Data Input | Strings or Objects | Strings | Objects | Strings |
| Weighting | ✅ Advanced | ❌ None | ⚠️ Basic | ❌ None |
| Return Type | Rich Result Object | Match Object | Original Item | [Score, String] |
| Maintenance | 🟢 Active | 🟡 Stable | 🟠 Check Status | 🟡 Stable |
fuse.js is the heavy lifter 🏋️. Use it when search quality is a core feature of your app. It handles nested data and scoring better than the rest.
fuzzy is the utility knife 🔪. Keep it in your back pocket for quick scripts or simple filters where adding a heavier dependency is not worth it.
fuzzy-search is the middle ground ⚖️. It structures data like fuse.js but with less configuration. Use it if fuse.js feels too complex, but verify maintenance first.
fuzzyset.js is the specialist 🎯. Use it when you need to correct a user's input to the closest known value, rather than returning a list of matches.
Final Thought: For most modern frontend applications, fuse.js provides the best balance of power and ease of use. Reserve the others for specific constraints like bundle size or unique algorithmic needs.
Choose fuse.js if you need a robust, feature-rich search engine for complex data structures. It supports weighted searches across nested object keys, custom scoring, and filtering. It is the industry standard for applications requiring high-quality search results with minimal setup.
Choose fuzzy if you need a lightweight, no-frills solution for simple string matching. It is ideal for basic filtering tasks where you do not need to search across multiple object properties or configure scoring thresholds. It works well for small lists and straightforward use cases.
Choose fuzzy-search if you want a middle ground between simplicity and structure. It allows searching across specific keys in a list of objects without the extensive configuration of fuse.js. However, verify its maintenance status before adopting, as it receives fewer updates than fuse.js.
Choose fuzzyset.js if your primary goal is typo correction or finding the single closest match rather than filtering a list. It uses Levenshtein distance to rank results by similarity score. It is best suited for autocomplete suggestions or data deduplication tasks.
Fuse.js is a lightweight, zero-dependency fuzzy-search library written in TypeScript. It works in the browser and on the server, and is designed for searching small-to-medium datasets on the client side where you can't rely on a dedicated search backend.
Multi-word fuzzy search with relevance ranking. Type "javascrpt paterns" and find "JavaScript Patterns" — typo tolerance, multiple words, and smart ranking all at once.
const fuse = new Fuse(docs, {
useTokenSearch: true,
keys: ['title', 'author', 'description']
})
fuse.search('javascrpt paterns')
// → [{ item: { title: 'JavaScript Patterns', ... } }]
See Token Search below for details.
Search large datasets without freezing the UI. FuseWorker splits your data across multiple Web Workers and searches in parallel — ~5x faster on 100K documents.
import { FuseWorker } from 'fuse.js/worker'
const fuse = new FuseWorker(docs, {
keys: ['title', 'author', 'description']
})
const results = await fuse.search('query')
fuse.terminate()
Same options and results as Fuse — just async. Function-valued options (sortFn, getFn, keys[].getFn) aren't supported because functions can't be transferred to a worker; everything else carries over. See the Web Workers docs for the interactive demo and full API.
npm install fuse.js
yarn add fuse.js
Or include directly via CDN:
<script src="https://cdn.jsdelivr.net/npm/fuse.js/dist/fuse.min.mjs"></script>
import Fuse from 'fuse.js'
const books = [
{ title: "Old Man's War", author: 'John Scalzi' },
{ title: 'The Lock Artist', author: 'Steve Hamilton' },
{ title: 'HTML5', author: 'Remy Sharp' },
{ title: 'JavaScript: The Good Parts', author: 'Douglas Crockford' }
]
const fuse = new Fuse(books, {
keys: ['title', 'author']
})
fuse.search('javscript')
// → [{ item: { title: 'JavaScript: The Good Parts', ... }, ... }]
The core of Fuse.js. Uses the Bitap algorithm for approximate string matching — handles typos, misspellings, and partial matches out of the box.
fuse.search('javscript')
// → [{ item: { title: 'JavaScript: The Good Parts', author: 'Douglas Crockford' } }]
Search across multiple fields with different importance levels. Title matches can rank higher than description matches.
const fuse = new Fuse(docs, {
keys: [
{ name: 'title', weight: 2 },
{ name: 'description', weight: 1 }
]
})
Use operators for precise control: exact match (=), prefix (^), suffix (!), and more. Enable with useExtendedSearch: true.
const fuse = new Fuse(list, {
useExtendedSearch: true,
keys: ['title']
})
fuse.search('=exact match') // exact match
fuse.search('^prefix') // starts with
fuse.search('!term') // does not include
Splits multi-word queries into individual terms, fuzzy-matches each independently, and ranks results using BM25-style IDF weighting. Enable with useTokenSearch: true.
const fuse = new Fuse(docs, {
useTokenSearch: true,
keys: ['title', 'body']
})
fuse.search('express midleware rout')
// Finds "Express Middleware" and "Express Routing Guide" despite typos
"patterns javascript" and "javascript patterns" return identical resultstokenMatch: 'all' returns only records matching every word (filtering); the default 'any' matches any wordtokenize for tokens with internal punctuation (node.js, c++), or use Intl.Segmenter for CJK / Thai word segmentation. Unicode-aware by defaultAvailable in the full build. See the Token Search docs for details and performance benchmarks.
Combine conditions with $and and $or for complex queries. Available in the full build.
fuse.search({
$and: [
{ title: 'javascript' },
{ author: 'crockford' }
]
})
Get character-level match indices for highlighting search results in your UI.
const fuse = new Fuse(list, {
includeMatches: true,
keys: ['title']
})
const result = fuse.search('javscript')
// result[0].matches[0].indices → [[0, 9]]
Use Fuse.match() to fuzzy-match a pattern against a single string without creating an index. Useful for one-off comparisons or custom filtering.
const result = Fuse.match('javscript', 'JavaScript: The Good Parts')
// → { isMatch: true, score: 0.04, indices: [[0, 9]] }
Fuse.match() does not support useTokenSearch — token search requires corpus-level statistics (df, fieldCount) that a one-off string comparison can't provide. Passing useTokenSearch: true throws an explicit error. Use new Fuse(docs, { useTokenSearch: true }).search(query) for token-search behavior.
Add and remove documents from a live index without rebuilding.
fuse.add({ title: 'New Book', author: 'New Author' })
fuse.remove((doc) => doc.title === 'Old Book')
Fuse.js ships in two variants:
| Build | Includes | Min + gzip |
|---|---|---|
| Full | Fuzzy + Extended + Logical + Token search | ~8.6 kB |
| Basic | Fuzzy search only | ~6.8 kB |
Use the basic build if you only need fuzzy search and want the smallest bundle size.
For the full API reference, configuration options, scoring theory, and interactive demos, visit fusejs.io.
See DEVELOPERS.md for setup, scripts, and project structure.
See CONTRIBUTING.md for guidelines on issues and pull requests.