
Fuse.js is a zero-dependency fuzzy search library that lets you search arrays of strings or objects on the client side with typo tolerance built in.
Feed it a data array, specify which fields to search, and get back scored, sorted results, even when the query contains misspellings.
Ideal for autocomplete inputs, command palettes, product search, documentation search, and any UI where users mistype queries or need to search across multiple fields with different relevance weights.
Features:
- Add typo-tolerant search to local datasets.
- Search strings, objects, nested fields, and arrays.
- Rank matches by field weight and text relevance.
- Highlight matching characters in search results.
- Match exact text, prefixes, suffixes, and excluded terms.
- Combine structured search conditions.
- Split multi-word queries into ranked terms.
- Search larger collections through Web Workers.
- Update live collections after initialization.
- Run in browsers, Node.js, and Deno.
Use Cases:
- Product catalog search where users type partial or misspelled product names and expect relevant matches.
- Documentation or wiki search where query terms rarely match headings exactly.
- Command palette inputs that match commands, shortcuts, and descriptions across multiple fields.
- Contact or user directory search across names, usernames, and email fields with weighted relevance.
How to use it:
1. Install Fuse.js with package managers when you use Vite, webpack, Rollup, Next.js, Astro, or another modern build tool.
# Yarn $ yarn add fuse.js # NPM $ npm install fuse.js
2. You can also load it from CDN in browser-only projects:
<script type="module" src="https://cdn.jsdelivr.net/npm/fuse.js/dist/fuse.min.mjs"></script>
3. Create a Fuse instance with your data array and a list of keys to search, then call search with a query string.
import Fuse from 'fuse.js';
const products = [
{ name: 'Wireless Headphones', brand: 'Sonique' },
{ name: 'Bluetooth Speaker', brand: 'BassBox' },
{ name: 'USB-C Hub', brand: 'LinkPro' },
];
// Initialize Fuse with data and the fields to search
const fuse = new Fuse(products, {
keys: ['name', 'brand'],
});
// Returns scored results even with typos in the query
fuse.search('headpones');
// → [{ item: { name: 'Wireless Headphones', brand: 'Sonique' }, refIndex: 0 }]
Advanced Usages:
Weighted Key Search for product search UI
Pass each key as an object with a name and a weight value. Higher weights move those fields up in the ranking.
const fuse = new Fuse(products, {
keys: [
{ name: 'name', weight: 3 }, // title matches rank higher
{ name: 'description', weight: 1 },
],
includeScore: true, // 0 = perfect match, 1 = no match
});
fuse.search('wireless');
Multi-Word Token Search
Enabling token search makes Fuse fuzzy-match each word independently and rank results using IDF weighting, so rare terms score higher than common ones.
const fuse = new Fuse(docs, {
useTokenSearch: true,
keys: ['title', 'body'],
});
// Each word is matched independently; typos are tolerated per term
fuse.search('javascrpt paterns');
// Finds "JavaScript Patterns" and similar results
// Require every word to match (AND mode)
const fuseStrict = new Fuse(docs, {
useTokenSearch: true,
tokenMatch: 'all',
keys: ['title', 'body'],
});
Token search is available in the full build only.
Extended Search Operators
When users need precise control over a query, enable useExtendedSearch to activate operator prefixes. These work alongside fuzzy matching in the same query string.
const fuse = new Fuse(catalog, {
useExtendedSearch: true,
keys: ['title', 'category'],
});
fuse.search('=USB-C Hub'); // exact match
fuse.search('^wireless'); // starts with "wireless"
fuse.search('$pro'); // ends with "pro"
fuse.search('!discontinued'); // does not include "discontinued"
fuse.search("'available"); // includes "available" as a substring
Logical Queries
Searching for records that must meet conditions across multiple fields requires a query object. Pass $and or $or with an array of field-pattern objects. The full build is required.
// Find items where title fuzzy-matches "hub" AND category is exactly "accessories"
fuse.search({
$and: [
{ title: 'hub' },
{ category: '=accessories' },
],
});
Match Highlighting
Character-level match indices let you wrap matched characters in highlight spans. Enable includeMatches and read the indices array from each result’s matches property.
const fuse = new Fuse(products, {
keys: ['name'],
includeMatches: true,
});
const results = fuse.search('wireles');
// results[0].matches[0].indices → [[0, 6]]
// Character range [0, 6] in the matched field should be highlighted
Dynamic Index Updates
Fuse supports live index updates for collections that change at runtime. Add or remove documents directly. No full rebuild is required.
// Add a new document to the live index
fuse.add({ name: 'Smart Watch', brand: 'TimeTech' });
// Remove documents matching a predicate; returns the removed items
fuse.remove((doc) => doc.discontinued === true);
// Remove the document at a specific array position
fuse.removeAt(2);
Web Worker Search
Searching 50,000 or more records synchronously on the main thread can drop frame rates. FuseWorker splits the work across multiple Web Workers and returns a Promise from its search method.
import { FuseWorker } from 'fuse.js/worker';
const fuse = new FuseWorker(largeDataset, {
keys: ['title', 'author'],
});
// search() returns a Promise; await it or chain .then()
const results = await fuse.search('typescript patterns');
// Terminate workers when the component unmounts
fuse.terminate();
Function-valued options such as sortFn and getFn are not transferable to Web Workers. All other options carry over.
Pre-Built Index
Large or frequently queried datasets benefit from pre-built indexes. Serialize the index once and parse it at runtime to skip re-indexing.
import Fuse, { createIndex } from 'fuse.js';
const keys = ['name', 'description'];
const myIndex = createIndex(keys, products);
// Persist or cache the JSON output
const serialized = myIndex.toJSON();
// At runtime, parse the stored index and pass it to the constructor
const parsedIndex = Fuse.parseIndex(serialized);
const fuse = new Fuse(products, { keys }, parsedIndex);
Configuration Options:
isCaseSensitive(boolean): Enables case-sensitive search. Defaults tofalse.ignoreDiacritics(boolean): Strips diacritical marks from characters before matching. Defaults tofalse.includeScore(boolean): Adds ascoreproperty to each result. A score of0is a perfect match;1is a complete mismatch. Defaults tofalse.includeMatches(boolean): Adds amatchesproperty with character-level index arrays for highlighting. Defaults tofalse.keys(array): The object fields to search. Accepts strings, dot-notation strings, or objects withnameandweight. Required for object datasets.shouldSort(boolean): Sorts results by score. Defaults totrue.sortFn(function): Custom sort function. Receives two scored result objects and must return a comparison number.findAllMatches(boolean): Continues scanning a string past the first match. Defaults tofalse.minMatchCharLength(number): Only returns matches where at least this many characters match. Defaults to1.location(number): Character index where the expected match is located in the string. Defaults to0.threshold(number): Match sensitivity.0.0requires a perfect match;1.0matches anything. Defaults to0.6.distance(number): How far the match can be from the expected location. Alocationof0anddistanceof100means characters at position 100 still count. Defaults to100.ignoreLocation(boolean): Ignores thelocationanddistanceoptions and searches the full string. Defaults tofalse.ignoreFieldNorm(boolean): Skips field-length normalization. Short and long fields receive identical weight. Defaults tofalse.fieldNormWeight(number): Controls how much field-length normalization affects the score. Higher values penalize long fields more. Defaults to1.useExtendedSearch(boolean): Activates extended search operators in query strings. Defaults tofalse.useTokenSearch(boolean): Splits multi-word queries into individual tokens and fuzzy-matches each. Requires the full build. Defaults tofalse.tokenize(RegExp or function): Custom tokenizer for token search. Useful for languages with no word boundaries or for special tokens likenode.jsorc++. Defaults toundefined, which uses Unicode word segmentation.tokenMatch(string): Set to'all'to require every token to match. Defaults to'any'.getFn(function): Custom function to extract values from nested objects. Receives a document and a path array.
API Methods:
// Search the indexed data. Returns an array of result objects.
// Pass { limit: n } as the second argument to cap result count.
const results = fuse.search('query', { limit: 5 });
// Add a single document to the live index.
fuse.add({ name: 'New Product', category: 'tools' });
// Remove documents matching a predicate. Returns the removed documents.
fuse.remove((doc) => doc.discontinued === true);
// Remove the document at the specified array index.
fuse.removeAt(3);
// Return the internal FuseIndex object.
fuse.getIndex();
// Static: build an index from keys and a data array.
const index = Fuse.createIndex(['name', 'description'], dataArray);
// Static: restore a pre-serialized index.
const restored = Fuse.parseIndex(serializedJSON);
// Static: match a pattern against a single string. Does not support useTokenSearch.
const match = Fuse.match('qurey', 'JavaScript query builder');
// → { isMatch: true, score: 0.12, indices: [[0, 4]] }
// Static: register searcher plugins.
Fuse.use(CustomSearcher);Alternatives:
- Fast Fuzzy Search In Pure JavaScript – fuzzysort
- Simple Performant Fuzzy Search Library – Microfuzz
- Fast Filtering (Fuzz-search) JavaScript Library – instafilter.js
FAQs
Q: What is the difference between the full build and the basic build?
A: The full build includes fuzzy search, extended search, logical queries, and token search. The basic build includes fuzzy search only. Import from fuse.js/basic to get the smaller 6.8 kB gzip bundle.
Q: How do I use Fuse.js in a React or Vue component?
A: Create the Fuse instance outside the render cycle, typically in a useMemo hook in React or a computed property in Vue. This prevents the index from rebuilding on every render. Pass the search query string to fuse.search inside an event handler or a reactive computed value.
Q: My search is returning too many irrelevant results. What should I adjust?
A: Lower the threshold option. The default is 0.6, which is fairly permissive. Try 0.3 or 0.4. Set ignoreLocation: false and keep distance low when your data has short strings. Enable includeScore: true to inspect how results are being scored.
Q: Can Fuse.js use a pre-built index stored in a static file or database?
A: Yes. Call myIndex.toJSON() on a FuseIndex object, cache the output, then call Fuse.parseIndex(data) at runtime and pass the result as the third argument to the Fuse constructor. This skips the indexing step entirely on the client.







