Fuzzy Search Library for Client-Side JavaScript – Fuse.js

Category: Javascript , Recommended | June 3, 2026
Authorkrisk
Last UpdateJune 3, 2026
LicenseMIT
Tags
Views0 views
Fuzzy Search Library for Client-Side JavaScript – Fuse.js

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 to false.
  • ignoreDiacritics (boolean): Strips diacritical marks from characters before matching. Defaults to false.
  • includeScore (boolean): Adds a score property to each result. A score of 0 is a perfect match; 1 is a complete mismatch. Defaults to false.
  • includeMatches (boolean): Adds a matches property with character-level index arrays for highlighting. Defaults to false.
  • keys (array): The object fields to search. Accepts strings, dot-notation strings, or objects with name and weight. Required for object datasets.
  • shouldSort (boolean): Sorts results by score. Defaults to true.
  • 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 to false.
  • minMatchCharLength (number): Only returns matches where at least this many characters match. Defaults to 1.
  • location (number): Character index where the expected match is located in the string. Defaults to 0.
  • threshold (number): Match sensitivity. 0.0 requires a perfect match; 1.0 matches anything. Defaults to 0.6.
  • distance (number): How far the match can be from the expected location. A location of 0 and distance of 100 means characters at position 100 still count. Defaults to 100.
  • ignoreLocation (boolean): Ignores the location and distance options and searches the full string. Defaults to false.
  • ignoreFieldNorm (boolean): Skips field-length normalization. Short and long fields receive identical weight. Defaults to false.
  • fieldNormWeight (number): Controls how much field-length normalization affects the score. Higher values penalize long fields more. Defaults to 1.
  • useExtendedSearch (boolean): Activates extended search operators in query strings. Defaults to false.
  • useTokenSearch (boolean): Splits multi-word queries into individual tokens and fuzzy-matches each. Requires the full build. Defaults to false.
  • tokenize (RegExp or function): Custom tokenizer for token search. Useful for languages with no word boundaries or for special tokens like node.js or c++. Defaults to undefined, 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:

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.

You Might Be Interested In:


Leave a Reply