
How to Implement Cmd-K Search in the Browser? A Comparison of fuse.js and Orama
Text by Tsuyoshi Hoshino
Published
Background and Goals
Many web applications feature a “Cmd+K / Ctrl+K” search palette for quickly finding content. We’re considering adding this Cmd-K search to Liam ERD, our ER diagram tool.
This article compares two search libraries, fuse.js and Orama, and explains why we ultimately decided to adopt fuse.js.
Liam ERD is open source, so we will also share PR(Pull Request) links to the PoC implementation and ADR (Architectural Decision Record) related to this feature.
Please note that the UI design for our Cmd-K search is still being discussed (the screenshots shown here are truly just placeholders; the actual design will be much more sick, we promise!), so this post focuses on the backend search engine aspect.
Requirements for Cmd-K Search
In Liam ERD, we want to implement a cross-referencing search for table names and column names displayed in the ER diagram.
We also offer both a Next.js-based web version and a CLI version that runs without a Node.js runtime, so we need to choose a browser-based search library that can support both environments.
We narrowed our candidates down to fuse.js and Orama because they both meet these requirements.
Why Compare fuse.js and Orama?
What is fuse.js?
- A lightweight JavaScript search library
- Specializes in fuzzy search, providing high accuracy even with default settings
- No pre-built index required—simply pass in an array to search
What is Orama?
- Utilizes an inverted index to theoretically achieve O(1) search speed
- Requires building an index ahead of time for high-speed searching
- May need additional tuning for partial matches or stemming
Because these two libraries use very different approaches, we felt it was worth integrating both into a real project to see how they performed.
PR #652: PoC for fuse.js and Orama
We first created a Proof of Concept (PoC) in PR #652 to implement Cmd-K search.
For testing, we used the Mastodon schema (about 99 tables) to simulate a data set of moderate size and complexity.
Comparison Criteria
-
Search Speed
⏳ ️How long each search takes on average?
⏳ Responsiveness for live (real-time) search inputs -
Initial Load Cost
⏳ Time spent building indices (especially for Orama)
⏳ Any delay before the UI is ready -
Fuzzy Search Accuracy
✓ Does the library handle typos well and return relevant results?
PoC Demonstration
We built a simple UI that switches between the two search engines via radio buttons, allowing us to compare their behavior:

Comparison of Search Results
Searching for “app”
When searching for “app”, both libraries return multiple matches for tables and columns containing “app”.
fuse.js | Orama |
---|---|
![]() | ![]() |
Searching for “apple”
Mastodon’s schema does not include any tables or columns with “apple”, but fuse.js still suggests closely related results. In contrast, Orama, which relies on precise indexing, returns no matches.
fuse.js | Orama |
---|---|
![]() | ![]() |
Overview of Test Results
From a performance standpoint, fuse.js is theoretically O(n), yet our tests showed it could respond in 0.1ms to 1.0ms, which felt extremely fast in practice. On the other hand, Orama aims for O(1) using an inverted index, but in practice, it produced search times similar to fuse.js, making any performance difference barely noticeable.
In terms of initial load cost, Orama requires 30ms–100ms for index creation at application startup. While that can lead to faster searches afterward, it may impact the app’s first-load time. Meanwhile, fuse.js has no indexing step, allowing the user to begin searching immediately.
Regarding fuzzy search accuracy, Orama excels at precise matching but struggles with slight typos or variations, such as “expire_at” vs. “expires_at.” In contrast, fuse.js can handle these quirks by default, offering robust fuzzy matching that easily accounts for typos.
Overall, while Orama provides theoretically outstanding search speed, the practical performance within a project of this size proved quite similar to fuse.js. Considering fuse.js’s simpler setup and stronger handling of typos, it emerged as the more pragmatic choice.
PR #675: The Decision to Adopt fuse.js
PR #675 formally introduced fuse.js as our solution. Here’s why:
- Ease of Integration
No index-building overhead; straightforward to use - Fuzzy Search Strength
Handles typos effectively; partial matches are simple to implement - Proven Real-World Performance
Demonstrated 0.1ms to 1.0ms response time for Mastodon-scale data
If the data set grows significantly and we run into search bottlenecks, we plan to re-evaluate Orama or other alternatives when the time is right.
Lessons Learned
One key takeaway is that real-world performance and development costs matter more than purely theoretical metrics. Although Orama advertises O(1) search, fuse.js performed remarkably well for small-to-medium data sets in actual measurements.
Additionally, the effort required to set up or tune the library is essential. Orama’s index-building and search tuning can be powerful but requires more overhead, while fuse.js has a simple API and provides user-friendly fuzzy search even with default settings. During initial development phases, having a quick-start solution like fuse.js can be advantageous.
We also learned that handling typos is a big part of any real-world search. Orama is well-suited for exact matches and partial matches but is less forgiving with genuine typos or slight spelling variants. fuse.js, on the other hand, does a great job with minimal configuration and is more flexible for these use cases.
We chose fuse.js for now, but if our data set expands and scalability becomes an issue, we can reevaluate Orama or other search libraries. Ultimately, selecting the best solution for the current stage is critical—sometimes you’re better off using a library that works immediately, rather than over-planning for potential future needs.
Our Decision
We compared fuse.js and Orama for implementing Cmd-K search, ultimately selecting fuse.js due to its simple integration and sufficient performance at our project’s scale.
In technology choices, it’s vital to test solutions in real environments instead of relying on theory alone. We hope our experience will help guide your own decisions when adding search functionality to your projects.
References
Text byTsuyoshi Hoshino
Tsuyoshi Hoshino is a software engineer at ROUTE06, Inc., working on Liam. He specializes in web application infrastructure and databases, holding the Information-Technology Engineer Examination(Database Specialist Examination). Passionate about Ruby, Rails, and all things cloud.
Last edited on