Library / SDK
nol13/fuzzball.js avatar
nol13/fuzzball.js

fuzzball.js: a JavaScript fuzzy matcher with token sort, wildcards and lite builds

Easy to use and powerful fuzzy string matching, port of fuzzywuzzy.

641 stars44 forksJavaScriptMIT

At a glance

What is it?
fuzzball is a JavaScript port of TheFuzz and RapidFuzz that scores string similarity and extracts the best matches from a list. It adds token similarity sorting and wildcard support on top of the Python algorithms, and ships lite and ultra lite builds for size sensitive environments.
Who is it for?
fuzzball suits JavaScript and TypeScript projects that need fuzzy matching for search boxes, name normalisation or deduplication without leaving the runtime, and it suits teams that want TheFuzz scoring semantics with a promise based extract that can be cancelled.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

fuzzball ports TheFuzz scoring to JavaScript and adds two things

fuzzball is described as easy to use and powerful fuzzy string matching, and the README is upfront that it is mostly a JavaScript port of the TheFuzz Python library, formerly known as fuzzywuzzy, and of the RapidFuzz library. Two additions on top of the ported algorithms are called out by name: the token similarity sort algorithm and wildcard support. The purpose of the library is narrow and specific. It answers a question that comes up constantly in user facing software: given a list of candidates and a query a human typed with the wrong spelling, which candidate did they mean, and how sure are you. The API is organised around two kinds of operation. The scorer functions compare two strings and return a number between 0 and 100, and the extract function takes a query and a list and returns the ranked matches. There is also a distance function that returns the unmodified Levenshtein distance with no ratio conversion on top, which is the one to reach for when you want a raw edit count rather than a normalised score. The package metadata describes it as fuzzy string matching algorithms and utilities, port of the TheFuzz Python library, with keywords covering levenshtein, fuzzy matching and search.

extract returns tuples, and returnObjects turns them into objects

The main entry point for real use is extract, and its return shape is worth understanding before you build on it. The README shows the whole flow, from requiring the package to choosing a scorer and running the query:

js
fuzz = require('fuzzball');

options = {scorer: fuzz.token_set_ratio};
choices = ["Hood, Harry", "Mr. Minor", "Mr. Henry Hood"];

fuzz.extract("mr. harry hood", choices, options);

// [choice, score, index/key]
[ [ 'Hood, Harry', 100, 0 ],
  [ 'Mr. Henry Hood', 85, 2 ],
  [ 'Mr. Minor', 40, 1 ] ]

Each result is a tuple of the chosen string, the score, and the index or key it came from. The index matters more than it looks, because extract works on objects as well as arrays, in which case that third element is the key rather than a position. If tuples are awkward in your code, the README documents an option that changes the shape: setting options.returnObjects to true gives back an array of objects with choice, score and key properties instead. The same query with the plain ratio scorer, which is what you get without passing options, is shown separately in the README, scoring "hello world" against "hiyyo wyrld" at 64 while the token set ratio scores "fuzzy was a bear" against "a fuzzy bear fuzzy was" at 100.

extractAsPromised can be cancelled with an AbortController

Searching a large list on every keystroke is where a synchronous API hurts, and fuzzball offers a promise based entry point for that case. extractAsPromised returns a promise, and the options object accepts an AbortController so the search can be abandoned. The README shows the shape of it:

js
const abortController = new AbortController();
options.abortController = abortController;

fuzz.extractAsPromised("gonna get canceled", choices, options)
        .then(res => {/* do stuff */})
        .catch((e) => {
                if (e.message === 'aborted') console.log('Search was aborted!')
        });

abortController.abort();

The cancellation is signalled through the rejection rather than a separate result, and the documented check is on the error message being the string aborted. That is a small but real integration detail: a caller has to inspect the message to tell an abort apart from a genuine failure, and the catch block in the README does exactly that before logging. Note that the abort controller is passed through the same options object that carries the scorer, so a single options object carries both configuration and control. The README also lists an async and cancellation section in its contents, alongside sections for batch extract, multiple fields, wildcards and fuzzy dedupe, which tells you the library covers a wider set of search patterns than the single extract call.

Four token-based scorers, and one of them is slower on purpose

The scorer set is the substance of the library, and the README explains each in a sentence. The simple ratio strips punctuation and lowercases in pre-processing by default, so "this is a test" and "This is a test!" score 100. The partial ratio scores the highest scoring substring of the longer string against the shorter one, which is why "test" and "testing" score 100. The token sort ratio tokenises, sorts and recombines before scoring, which makes "fuzzy wuzzy was a bear" and "wuzzy fuzzy was a bear" score 100 where the plain ratio gives 91. The token set ratio takes the highest of three scores comparing the set intersection, the intersection plus difference one way, and the intersection plus difference the other way, so "fuzzy was a bear" and "fuzzy fuzzy was a bear" score 100 where the token sort ratio gives 84. The odd one out is the token similarity sort ratio, which sorts tokens by similarity to the smaller set rather than alphabetically, useful when the matching token may start with a different letter. The README is candid that it performs a bit slower, and that it is not available in the lite builds, and that the sorting does not yet take wildcards or collation into account. The same similarity sort can be used inside token_set_ratio by setting sortBySimilarity to true, which raises the documented score for that example from 61 to 71.

Pre-processing is on by default and can be run ahead of time

Before any scoring happens, strings are cleaned. The README states that pre-processing to remove non alphanumeric characters runs by default unless options.full_process is set to false, and shows what that costs you in score when you switch it off:

js
fuzz.ratio("this is a test", "this is a test!", {full_process: false});
        97

The same cleaning can be run as a separate step, and the README recommends doing it beforehand to avoid a bit of performance overhead:

js
fuzz.full_process("myt^eäXt!");
        myt eäxt
fuzz.full_process("myt^eäXt!", {force_ascii: true});
        myt ext

Two options shape that step. force_ascii, defaulting to false, removes all non ascii letters as well, which is what turns the second result into myt ext. Consecutive white space is collapsed unless options.collapseWhitespace is false, and the README notes that setting it to false matches the behaviour in fuzzywuzzy, and that it only affects the non token scorers. The distinction matters when you are comparing numbers against a Python implementation and find small differences. Collapsing whitespace and stripping punctuation are separate decisions with separate switches, so you can match either implementation's behaviour deliberately rather than by accident.

The lite and ultra lite builds drop features to shrink the file

fuzzball ships three build variants and the choice is made at import time through the package exports map in package.json. The main entry is fuzzball, with the CommonJS file fuzzball.js and the ES module at dist/esm/fuzzball.esm.min.js. The ./lite subpath resolves to lite/fuzzball_lite.js and the lite ES module, and ./ultra_lite resolves to the equivalents under ultra_lite/. The repository root shows the directories behind this, with lite/ and ultra_lite/ alongside dist/, lib/, test/, demo-app/ and jsdocs/, plus a rollup.config.js and an esmwrapper.js. The README says to look at the lite section if you need the smallest possible file size, and the contents list a lite versions section as well as a benchmark.js at the root of the repository. The concrete feature cost of the lite builds appears in the scoring section, where the token similarity sort algorithm is described as not available in the lite builds. So the trade is not simply smaller versus bigger, it is smaller versus a specific scorer, and the wildcard and collation interactions with similarity sorting are also flagged as unfinished in that area. Everything else, including the scorers ported from TheFuzz, remains. The package is published under the MIT licence, and the last push to the repository was on 2026-10-18, with the listed releases being v2.2.6 on 2026-04-30, v2.2.3 on 2025-08-15 and v2.2.1 on 2025-03-18. The README also warns that anyone on Internet Explorer or Node older than 14 should use v2.1.6 or earlier.

Collation has a performance cost and the README says so

Unicode handling is where the port diverges from the Python original in cost. To use collation when calculating edit distance, the README says to set useCollator to true, and it warns that this will have an impact on performance, so if you have a really large number of choices it may be best to pre-process with lodash _.deburr instead if possible. That is a specific and useful piece of advice rather than a general warning. Collating means constructing a collator and comparing strings under locale rules rather than by code point, and the cost shows up directly in the hot loop over your candidate list. The README's alternative is to normalise the strings once before the search, using lodash's deburr to strip diacritics, which moves the work outside the per-comparison path. The example in that section of the README is cut off in the copy available here, so the exact call signature is not shown, but the option name and the trade-off are stated plainly. The same theme runs through the wildcards and collation caveat on similarity sorting, where the README notes that the sorting does not yet take wildcards or collation into account. This is an area where the library is explicit about its limits rather than silent.

Editorial conclusion

fuzzball suits JavaScript and TypeScript projects that need fuzzy matching for search boxes, name normalisation or deduplication without leaving the runtime, and it suits teams that want TheFuzz scoring semantics with a promise based extract that can be cancelled. It is the wrong choice if you need the full breadth of RapidFuzz scoring in Python and can run Python, and it is the wrong choice if your Node version is below 14 or you must support Internet Explorer, since the README directs those users to v2.1.6 or earlier. Verify first that the scorer you need exists in the build you import, because the lite builds drop the token similarity sort algorithm, and check the abort behaviour of extractAsPromised before you rely on it to cancel a long search.

Frequently asked questions

How do I install fuzzball and score two strings?

Install it with npm install fuzzball, then require the package and call a scorer such as fuzz.ratio, which returns a number between 0 and 100 after default pre-processing that lowercases and strips non alphanumeric characters.

How does fuzzball find the best match in a list?

Use fuzz.extract with the query, the choices and an options object. It returns tuples of choice, score and index or key, and setting options.returnObjects to true returns objects with choice, score and key properties instead.

Can a fuzzball search be cancelled?

Yes. Pass an AbortController in the options object to fuzz.extractAsPromised, then call abort on it. The promise rejects with an error whose message is aborted, so callers should check for that message.

What is the difference between the fuzzball lite builds?

The package exports a ./lite and an ./ultra_lite subpath alongside the main entry, for users who need the smallest possible file size. The README notes the token similarity sort algorithm is not available in the lite builds.

Official sources

  1. Issues
  2. License: MIT
  3. nol13/fuzzball.js on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nol13-fuzzball-js.svg)](https://hysenlabs.com/projects/nol13-fuzzball-js)

Was this useful?