CLI tool
ankane/searchkick avatar
ankane/searchkick

Searchkick: SQL-style search for Rails backed by Elasticsearch or OpenSearch

Intelligent search made easy

6,721 stars761 forksRubyMIT

At a glance

What is it?
Searchkick is a Ruby gem that puts a query DSL in front of Elasticsearch or OpenSearch and keeps the index in sync with Active Record or Mongoid models. It fits teams that already run a search server and want to stop hand-building JSON.
Who is it for?
Adopt Searchkick if you run a Rails or Mongoid app, you already operate Elasticsearch 8 or 9 or OpenSearch 2 or 3, and your team would rather write Ruby than search-server JSON. Do not adopt it if you cannot run a separate search cluster, or if the default 10,000-result paging limit breaks a screen you already ship.
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 Ruby, according to GitHub's language statistics.

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

From daily snapshots

Star history

  • ankane/searchkick6,721 ★ · +2
Star history
Repository2026-09-232026-11-14
ankane/searchkick6.7k6.7k

2 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What Searchkick actually removes from a Rails search feature

The gem's premise is that most product search is a relevance problem wrapped in a plumbing problem. Searchkick takes the plumbing. You mark a model with a single call, and the gem maps that model's columns into an index, keeps the index current as records change, and exposes a query interface that reads like Active Record. That last part is the real selling point. Instead of assembling a query body by hand and posting it to a cluster, you write chains such as Product.search("apples").where(in_stock: true).limit(10).offset(50), which the README presents directly under the heading "Query like SQL".

The audience is narrow and specific: Ruby developers on Rails or Mongoid who already have, or are willing to operate, an Elasticsearch or OpenSearch cluster. Searchkick does not embed a search engine. It is a client and an indexing layer. If you have no cluster, the gem gives you nothing to talk to.

The relevance features are the second half of the pitch. The README lists stemming (tomatoes matches tomato), special characters (jalapeno matches jalapeño), extra whitespace (dishwasher matches dish washer), misspellings (zuchini matches zucchini), and custom synonyms (pop matches soda). Those are search-server capabilities that Searchkick configures and exposes rather than invents, but wiring them by hand is the tedious part most teams skip.

Indexing, callbacks and the reindex path

Searchkick sits between your database and the search server. The model is the source of truth. Adding searchkick to a class registers it for indexing, and Product.reindex pushes the current rows into the search index. From then on, the gem's callbacks keep records in sync as they are created, updated and destroyed.

Queries return a Searchkick::Relation, which the README says responds like an array to most methods. There is a meaningful detail in how results are materialized. By default, ids come back from the search server and the records themselves are fetched from your database. That is a second round trip, and it means a stale index can return ids for rows that no longer exist. The alternative is Product.search("apples").load(false), which fetches everything from the search server and skips the database entirely.

The README also exposes results.total_count, results.took in milliseconds, and results.response for the raw server reply. Those three are the minimum you need to debug a relevance complaint, and having them on the relation rather than buried in a client object is a sensible design choice.

Installing Searchkick and running a first search

The README assumes a search server is already running. For Homebrew users it gives two commands, one to install OpenSearch and one to start it as a service.

sh
brew install opensearch
brew services start opensearch

Then the Gemfile needs Searchkick plus exactly one client gem. The README marks both client lines as "select one", so adding both is a mistake.

ruby
gem "searchkick"

gem "elasticsearch"   # select one
gem "opensearch-ruby" # select one

Version compatibility is stated plainly: the latest version works with Elasticsearch 8 and 9 and OpenSearch 2 and 3. Elasticsearch 7 and OpenSearch 1 require version 5.5.2 and a separate readme, which is the kind of boundary worth checking before you upgrade a cluster.

Adding search to a model is one line inside the class body.

ruby
class Product < ApplicationRecord
  searchkick
end

Populate the index, then query it. After Product.reindex finishes, the first search should return Product records, and calling .name on each one should print the attribute from your database.

ruby
Product.reindex

products = Product.search("apples")
products.each do |product|
  puts product.name
end

One caveat before you rely on the defaults: the README states that results must match all words in the query, so "fresh honey" means fresh AND honey. If you want either word, chain .operator("or"). And a search for "back" will not match "backpack" unless you declare word_start on the field and reindex, then query with .fields(:name).match(:word_start).

The 10,000-result ceiling and other places Searchkick is the wrong tool

The most concrete limitation in the README is paging. Elasticsearch and OpenSearch limit paging to the first 10,000 results by default, and the README notes explicitly that this applies to the total count as well. If your interface shows a result count or offers deep pagination, that number is capped. Searchkick does not hide this; it documents it.

The second limitation is architectural. Searchkick needs a running Elasticsearch or OpenSearch cluster. That is a separate service to deploy, monitor, back up and version. For a small application with a few thousand rows, that is a large amount of operational surface for the benefit. Postgres full-text search or a simpler index will often be the better answer, and Searchkick's own design does not pretend otherwise.

The third is the callback model. Automatic indexing on model writes is convenient, and it is also the part most likely to surprise you in production, because index updates now happen inside your write path. If your write volume is high or your reindex is slow, check how indexing behaves before you depend on it.

Searchkick versus querying Elasticsearch directly

The honest alternative is not another gem. It is the official elasticsearch or opensearch-ruby client, used directly. The difference in approach is where the query language lives. With the raw client you build request bodies as hashes and manage index mappings, analyzers and reindexing yourself. You get the complete API surface with nothing abstracted away, and no version of Searchkick stands between you and a feature the search server shipped last month.

Searchkick's answer to that is documented rather than hidden. The README states that Searchkick supports the complete Elasticsearch Search API and OpenSearch Search API, and that as your search becomes more advanced it recommends the search server DSL for maximum flexibility. In other words, the gem expects you to outgrow its convenience layer on the hardest queries, and it gives you a path to do so from inside the same relation object rather than forcing a rewrite.

That is a reasonable position. The cost is a second mental model: you learn the Ruby DSL for the common cases and the server DSL for the rest, and you need to know which one a given chain is using when results look wrong. Teams with one or two complex queries and a lot of simple ones will find that acceptable. Teams whose search is entirely bespoke will find the DSL is overhead.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-10-27. The CHANGELOG.md file at the repository root is where release history lives. The repository has no published GitHub releases, so treat the changelog as the source of truth for what changed between versions.

The licence is MIT, listed in LICENSE.txt. That is permissive: it allows commercial use, modification and redistribution, provided the copyright notice and permission notice are retained. This is a description of the licence text, not legal advice; if your organisation has specific obligations around attribution or dependency review, run it past whoever handles that.

The upgrade cost is dominated by search-server compatibility, not by the gem itself. The README draws a hard line at Elasticsearch 7 and OpenSearch 1, which need Searchkick 5.5.2 and a different readme. That means a cluster upgrade and a gem upgrade are coupled. Plan them together, and check the changelog before touching either.

Editorial conclusion

Adopt Searchkick if you run a Rails or Mongoid app, you already operate Elasticsearch 8 or 9 or OpenSearch 2 or 3, and your team would rather write Ruby than search-server JSON. Do not adopt it if you cannot run a separate search cluster, or if the default 10,000-result paging limit breaks a screen you already ship. Before committing, run Product.reindex on a staging copy and time it, decide whether the default callback-driven indexing fits your write path, and confirm which client gem your cluster version requires.

Frequently asked questions

What is the Searchkick gem used for?

It connects Ruby models to Elasticsearch or OpenSearch and gives you a query interface that reads like SQL, plus indexing, reindexing without downtime, autocomplete and "Did you mean" suggestions. It is aimed at Rails and Mongoid applications that already run a search server.

How do I install Searchkick in a Rails app?

Add the searchkick gem to your Gemfile along with exactly one client gem, either elasticsearch or opensearch-ruby, then call searchkick inside the model class and run Product.reindex to populate the index. The README shows installing and starting OpenSearch with Homebrew before any of that.

Which versions of Elasticsearch and OpenSearch does Searchkick support?

The README states the latest version works with Elasticsearch 8 and 9 and OpenSearch 2 and 3. For Elasticsearch 7 and OpenSearch 1 you need version 5.5.2 and a separate readme.

Why does Searchkick only return the first 10,000 results?

Elasticsearch and OpenSearch limit paging to the first 10,000 results for performance by default, and the README notes this applies to the total count as well. The README links this note to a separate deep paging section.

Official sources

  1. ankane/searchkick on GitHub
  2. Issues
  3. License: MIT
  4. README
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/ankane-searchkick.svg)](https://hysenlabs.com/projects/ankane-searchkick)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/ankane-searchkick.svg)](https://hysenlabs.com/projects/ankane-searchkick)

Was this useful?