fuse.js, fuzzy-search, and fuzzyset are JavaScript libraries designed to perform approximate string matching directly in the browser. They allow users to find relevant results even when typos occur or when the search term does not exactly match the data. fuse.js is a lightweight fuzzy-search module that supports weighted searching across object properties. fuzzy-search provides a simple interface for filtering arrays of objects based on multiple keys. fuzzyset focuses on creating a set of strings for fast lookup and scoring, often used for deduplication or simple matching tasks.
When building search features in web applications, exact matching often frustrates users. A single typo can yield zero results. Fuzzy search libraries solve this by finding matches based on similarity rather than exact equality. fuse.js, fuzzy-search, and fuzzyset are three popular choices, but they differ significantly in algorithm, data handling, and flexibility. Let's examine how they perform in real engineering scenarios.
The core difference lies in how each library calculates similarity. This affects both performance and result relevance.
fuse.js uses the Bitap algorithm. It supports location-based scoring, meaning matches closer to the start of the text rank higher. It also allows threshold tuning to filter out weak matches.
// fuse.js: Configurable threshold and location bias
import Fuse from 'fuse.js';
const fuse = new Fuse(items, {
keys: ['title', 'author'],
threshold: 0.3,
location: 0
});
const results = fuse.search('harry potter');
// Returns items with score and match details
fuzzy-search uses a simpler fuzzy matching approach optimized for speed on lists. It ranks results but offers less control over the scoring algorithm itself.
// fuzzy-search: Simple key-based matching
import FuzzySearch from 'fuzzy-search';
const searcher = new FuzzySearch(items, ['title', 'author'], {
caseSensitive: false
});
const results = searcher.search('harry potter');
// Returns filtered array of items directly
fuzzyset relies on Levenshtein distance for string sets. It is designed for matching against a set of unique strings rather than weighted object properties.
// fuzzyset: String set matching
import fuzzyset from 'fuzzyset';
const set = fuzzyset(['harry potter', 'harry porter', 'lord of the rings']);
const results = set.get('harry potter');
// Returns array of [score, string] tuples
Your data shape dictates which library fits best. Some handle objects natively, while others expect plain strings.
fuse.js excels with nested objects. You can search deep properties without flattening your data first. It returns the original item along with match metadata.
// fuse.js: Nested object support
const fuse = new Fuse(users, {
keys: ['profile.name', 'profile.bio']
});
const results = fuse.search('developer');
// results[0].item contains the full user object
fuzzy-search works with arrays of objects but expects flat keys. It returns the matching items directly, which simplifies rendering but hides scoring data.
// fuzzy-search: Flat key support
const searcher = new FuzzySearch(users, ['name', 'bio']);
const results = searcher.search('developer');
// results is an array of user objects
fuzzyset is built for arrays of strings. If you have objects, you must extract the searchable text manually before indexing.
// fuzzyset: String array only
const titles = users.map(u => u.name);
const set = fuzzyset(titles);
const results = set.get('dev');
// results contains [score, name] tuples, not full objects
Complex applications often require fine-tuning to balance performance and relevance. The level of control varies widely.
fuse.js offers extensive options. You can weight keys, ignore tokens, and adjust distance limits. This is crucial for large datasets where noise is a problem.
// fuse.js: Advanced weighting
const fuse = new Fuse(items, {
keys: [
{ name: 'title', weight: 0.8 },
{ name: 'tags', weight: 0.2 }
],
ignoreLocation: true,
minMatchCharLength: 2
});
fuzzy-search keeps configuration minimal. You can toggle case sensitivity and sort results, but deep tuning is not available. This reduces setup time but limits optimization.
// fuzzy-search: Basic options
const searcher = new FuzzySearch(items, ['name'], {
caseSensitive: false,
sort: true
});
fuzzyset has very few options. It focuses on speed and simplicity for string sets. You can adjust the default exact match threshold, but little else.
// fuzzyset: Minimal config
const set = fuzzyset(null, true); // useLevenshtein = true
set.add('example string');
How the results are returned affects how you write your UI logic. Some return scores, others return items.
fuse.js returns an array of result objects containing the item, score, and match indices. This allows you to highlight matched text or sort by relevance manually.
// fuse.js: Rich result object
const results = fuse.search('query');
results.forEach(result => {
console.log(result.item); // The data
console.log(result.score); // The relevance
});
fuzzy-search returns the filtered array of items directly. This is convenient for simple lists but makes highlighting or custom sorting harder.
// fuzzy-search: Direct items
const results = searcher.search('query');
results.forEach(item => {
console.log(item); // The data only
});
fuzzyset returns tuples of score and string. You must map these back to your original data if you stored only strings in the set.
// fuzzyset: Score tuples
const results = set.get('query');
results.forEach(([score, string]) => {
console.log(string); // The matched string
console.log(score); // The relevance
});
Long-term projects require libraries that are kept up to date with modern JavaScript standards.
fuse.js is actively maintained with regular updates. It supports ES modules, TypeScript definitions, and server-side rendering environments. It is the safest choice for new projects.
// fuse.js: Modern import
import Fuse from 'fuse.js';
// Fully typed with TypeScript
fuzzy-search is stable but sees fewer updates. It works well for standard use cases but may lack features for edge cases. It is suitable for internal tools or simple interfaces.
// fuzzy-search: Standard import
import FuzzySearch from 'fuzzy-search';
// CommonJS and ES module support available
fuzzyset has seen less activity in recent years. While functional, it may not align with modern build tools without extra configuration. Use with caution in large-scale applications.
// fuzzyset: Legacy-style import
import fuzzyset from 'fuzzyset';
// Check for modern module compatibility
| Feature | fuse.js | fuzzy-search | fuzzyset |
|---|---|---|---|
| Algorithm | Bitap with scoring | Simple fuzzy match | Levenshtein distance |
| Data Input | Objects or Strings | Objects | Strings only |
| Output | Item + Score + Indices | Items only | Score + String tuples |
| Configuration | Extensive | Minimal | Very Limited |
| Best Use | Complex search UI | Simple filtering | String deduplication |
fuse.js is the robust choice for most professional applications. It handles objects natively, provides detailed match data for UI enhancements, and offers the control needed for tuning relevance. Use it for customer-facing search bars, documentation sites, or large datasets.
fuzzy-search is ideal for quick implementations where speed of development matters more than fine-tuning. It works well for admin panels, internal dashboards, or small lists where default behavior is acceptable.
fuzzyset serves a niche role for string sets and deduplication tasks. Unless you have a specific need for its string-set architecture, prefer fuse.js for general searching needs to ensure long-term maintainability.
Final Thought: All three libraries solve the typo problem, but fuse.js provides the engineering depth required for scalable, user-friendly search experiences.
Choose fuse.js if you need advanced configuration options like weighting specific fields, setting threshold scores, or handling complex nested objects. It is the industry standard for production-grade fuzzy search where accuracy and flexibility matter most. This library is actively maintained and supports modern JavaScript environments without heavy dependencies.
Choose fuzzy-search if you want a straightforward solution for filtering lists of objects with minimal setup. It works well for simple UI components like dropdowns or command palettes where deep customization is not required. The API is concise, making it easy to integrate quickly without learning complex configuration options.
Choose fuzzyset if you are working primarily with flat arrays of strings rather than complex objects. It is suitable for tasks like deduplication or checking membership with approximate matching. However, evaluate its maintenance status carefully as it offers fewer features for object-based searching compared to modern alternatives.
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.