Chewy for Ruby: Elastic mapping, indexing, and Rails search
High-level Elasticsearch Ruby framework based on the official elasticsearch-ruby client
At a glance
- What is it?
- Chewy adds model-aware indexing, document mapping, update strategies, and a chainable query DSL to the official Elasticsearch Ruby client. It fits Rails applications that need related records reindexed, but its non-SemVer upgrade policy requires careful release checks.
- Who is it for?
- Adopt Chewy when a Rails or Ruby application needs model-aware Elasticsearch indexing and accepts responsibility for keeping its index classes, callbacks, and deployment configuration aligned with the database. Do not choose it merely to access Elasticsearch without adding an abstraction layer, or if a strict SemVer upgrade contract is required.
- 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 5 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 October 25, 2026, and from our analysis. They are not legal advice.
Star history
- toptal/chewy1,901 ★ · +0
| Repository | 2026-10-16 | 2026-10-25 |
|---|---|---|
| toptal/chewy | 1.9k | 1.9k |
0 Stars in the last 9 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Why Chewy sits above elasticsearch-ruby
Chewy is an object document mapper for Elasticsearch, not a replacement Elasticsearch transport. It is built on the official `elasticsearch-ruby` client and adds conventions for indexes, document import, model-derived fields, update behavior, and query construction. The direct audience is Ruby developers who want search indexes to follow application model changes without manually assembling every client request and then remembering which model updates affect which index.
Its distinguishing feature is cross-model observability. A `UserIndex` can expose the fields it expects from `User`, while related models can each declare an updateable index. The README gives tags stored with an article as the motivating case: when a tag changes, corresponding articles can be reindexed. This is useful for denormalized documents because Chewy treats related data as something to preserve at indexing time, rather than leaving each application service responsible for discovering every affected document.
Chewy also collects changed objects within an atomic update block and sends one index update at the end. The bulk API is also used for full reindexing and index updates. The query interface is chainable, mergeable, lazy, and modeled partly after Active Record queries, with object-oriented query and filter builders. For a Rails application, these abstractions reduce the amount of index and synchronization code that lives outside the model definitions.
The cost is an additional mapping layer. Applications must define what Chewy indexes, when callbacks fire, how environments differ, and how lifecycle work handles Chewy's thread-local clients. A direct `elasticsearch-ruby` integration is simpler when the application needs a narrow set of Elasticsearch calls and already has a separate indexing policy.
Install Chewy and connect the Elasticsearch test service
The simplest documented installation adds Chewy to the application's `Gemfile` and resolves the bundle.
gem 'chewy'This declares the dependency. `bundle` then installs the gems recorded for that application.
$ bundleFor a direct local installation outside Bundler, the README also documents the following command.
$ gem install chewyThe getting-started instructions use `config/initializers/chewy.rb` to define a minimal host setting.
Chewy.settings = {host: 'localhost:9250'}The `9250` port corresponds to the repository's `docker-compose.yml`, which exposes Elasticsearch as `127.0.0.1:9250:9200`. The README's longer Docker example instead uses host port `9200`; those two documented setups are not interchangeable without adjusting the configured host. The generated Rails configuration separates test and development environments.
# config/chewy.yml
test:
host: 'localhost:9250'
prefix: 'test'
development:
host: 'localhost:9200'The generator command writes that file.
$ rails g chewy:installThe test configuration should therefore point to `localhost:9250` when using the repository's Compose service. The README also warns that Elasticsearch 8 enables security by default. Its local testing command disables that feature, while the production-oriented configuration example adds a user, password, and CA file.
Define UsersIndex and attach model callbacks
A Chewy index maps model data to an Elasticsearch document. The README's `UsersIndex` configures a custom email analyzer, scopes itself to `User`, declares indexable fields, and selects the email analyzer for that field.
class UsersIndex < Chewy::Index
settings analysis: {
analyzer: {
email: {
tokenizer: 'keyword',
filter: ['lowercase']
}
}
}
index_scope User
field :first_name
field :last_name
field :email, analyzer: 'email'
}The `keyword` tokenizer and lowercase filter are Elasticsearch analysis settings embedded in the index definition. The keyword tokenizer preserves the email as one token, while lowercase normalizes casing. That choice may be useful for email-oriented matching, but the documentation does not claim that it implements a particular address validation scheme.
After the Active Record model, table, and migration exist, the model can register `update_index`. Place the index class in `app/chewy/users_index.rb` and add the callback in the `User` model.
class User < ApplicationRecord
update_index('users') { self }
endThe block supplies the object Chewy should index. The callback is the integration point between a database model change and Elasticsearch. That is also where application-specific decisions belong. For example, the README does not document conditional indexing, deletion handling, or a rollback procedure in the shown configuration, so those behaviors should not be inferred.
For a Rails application, the documented model generation and migration sequence is:
$ bundle exec rails g model User first_name last_name email
$ bundle exec rails db:migrateOnce records exist, the README states that creating a `User` also creates the corresponding User index entry. This callback-based model is more immediate than requiring every write path to remember a separate search indexing call, but its scope must remain consistent with the application's transaction and deletion semantics.
Issue a lazy UsersIndex query from Rails
Chewy's query DSL accepts Elasticsearch-style query components while returning a chainable query object. In the README example, `UsersController#search` builds a `query_string` request across several user fields and serializes the result as JSON.
def search
@users = UsersIndex.query(query_string: { fields: [:first_name, :last_name, :email, ...], query: search_params[:query], default_operator: 'and' })
render json: @users.to_json, status: :ok
endThe permitted parameters are declared separately.
private
def search_params
params.permit(:query, :page, :per)
endThis example demonstrates query construction, but the README does not show how `page` and `per` are passed to Elasticsearch or how the resulting total is exposed to a user. The example also contains an ellipsis in the `fields` array, so it cannot be copied as a complete production query without selecting the real fields.
The important integration detail is that the controller asks `UsersIndex`, rather than constructing an Elasticsearch client request. This keeps field names and index behavior close to the index definition, although controllers still need to enforce application authorization and decide how pagination and result metadata should work. The README does not document authentication for the search endpoint or a framework-specific pagination adapter in this example.
For non-Rails use, the installation still works through RubyGems, but the presented setup and model callback are Rails-specific. The rest of the framework provides index handling and querying, yet choosing it outside Rails means defining equivalent application integration conventions.
Connection cleanup exposes a thread-local constraint
Chewy memoizes `Chewy.client` per thread, so each thread receives a client and connection set. The README says neither `elasticsearch-ruby` nor `elastic-transport` offers a public API for closing those connections. Under normal garbage collection, the client and its file descriptors are reclaimed only after Ruby collects them.
That design can become a file-descriptor leak in long-lived, multithreaded processes that repeatedly create and discard threads, including a Sidekiq failure path that replaces a worker thread. Chewy exposes `Chewy.close_client` for this case.
Chewy.close_clientThis closes the current thread's connections and drops its memoized client. A later `Chewy.client` call constructs a new one. The call is thread-local, so cleanup logic must execute in the same thread that used Chewy. The documentation does not provide a global close operation or promise that callers can safely close another thread's client.
This is a concrete adoption criterion for background job systems, thread pools, and other long-running workers. A Rails request process may not encounter the same discarded-thread pattern as a persistent worker, but its threads should still be considered where the application owns explicit worker lifecycle. The repository gives a narrow command for client cleanup, not a complete resource policy for every deployment topology.
Version alignment and the cost of Chewy upgrades
Chewy's compatibility is tied to Ruby, Active Record, and Elasticsearch versions rather than only to its own API surface. The README states compatibility with MRI 3.2 through 4.0 and lists Active Record 7.2 and 8.0 as supported. Its matrix maps Chewy 8.0.x to Elasticsearch 8.x, while earlier Chewy lines target earlier Elasticsearch generations.
The upgrade warning is unusually direct: Chewy does not follow SemVer, so minor version bumps may contain breaking changes. Its major line is associated with the newest supported Elasticsearch version, but that relationship does not make every upgrade routine. The repository includes `migration_guide.md`, `CHANGELOG.md`, and `spec/` as the places to inspect before changing versions.
For applications, this means an upgrade can require code review rather than only lockfile resolution. Index classes, mappings, query construction, model callbacks, and supported cluster behavior all need alignment. Elasticsearch 8 security also affects connection configuration. The README documents `user`, `password`, and `transport_options` with an SSL `ca_file`, while its local Docker example disables security. A deployment should not copy the local test setting into an environment where authentication is required.
Chewy is released under the MIT license, as stated in the repository metadata and its `LICENSE.txt`. That permits use and modification under the license's conditions, but operators still need to review the actual license text and dependency licenses for their application. License choice does not reduce the technical upgrade work created by Elasticsearch compatibility.
Choose between Chewy and direct elasticsearch-ruby requests
The official `elasticsearch-ruby` gem is the appropriate lower-level choice for an application that only sends explicitly defined Elasticsearch requests. It exposes the client without requiring Chewy index classes, model callbacks, atomic update behavior, or a Chewy query object. Direct access leaves indexing policy in application services, jobs, or domain-specific code.
Chewy is more useful when database models and search documents are coupled. Its `update_index` callback, updateable per-model indexes, bulk import behavior, and atomic update strategy are mechanisms that would otherwise need custom coordination. That coordination is particularly relevant when denormalized documents contain related records and one related update must affect several indexed objects.
The tradeoff is reduced explicitness at the application boundary. Developers must understand which model owns an update, when callbacks execute, how documents are imported, and whether Chewy's query abstraction matches the required Elasticsearch feature. Chewy does not cover every concern of a search application. The README does not document deployment-time reindex coordination, migration rollback, pagination integration, or result authorization, so these remain separate application responsibilities.
A small service with a few static index calls should start with the official client if it has no model-sync requirement. A Rails application with recurring model changes, denormalized search documents, or repeated reindex operations gets more value from Chewy's conventions. The deciding factor is not query syntax alone, but whether the application wants Chewy to own model-to-index coordination.
Editorial conclusion
Adopt Chewy when a Rails or Ruby application needs model-aware Elasticsearch indexing and accepts responsibility for keeping its index classes, callbacks, and deployment configuration aligned with the database. Do not choose it merely to access Elasticsearch without adding an abstraction layer, or if a strict SemVer upgrade contract is required. Before adoption, verify compatibility among the selected Chewy release, Elasticsearch cluster, Ruby version, Active Record version, connection lifecycle, and security configuration; the repository states that Chewy 8.0.x targets Elasticsearch 8.x and supports MRI 3.2 through 4.0.
Frequently asked questions
How do I install Chewy in a Ruby application?
Add `gem 'chewy'` to the application's `Gemfile` and run `bundle`. The README also documents `gem install chewy` for a direct installation.
Which Elasticsearch version supports Chewy 8.0.x?
The compatibility matrix maps Chewy 8.0.x to Elasticsearch 8.x. It also lists MRI 3.2 through 4.0 and Active Record 7.2 and 8.0 as supported.
How does Chewy update Elasticsearch when an Active Record model changes?
An Active Record model can register an `update_index` callback. The README's `User` example uses `update_index('users') { self }` to connect record changes to the Users index.
Does Chewy follow Semantic Versioning?
No. The README explicitly states that Chewy does not follow SemVer and warns that minor version bumps may include breaking changes, so release notes and the migration guide need review before upgrades.
Official sources
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.
[](https://hysenlabs.com/projects/toptal-chewy)Star history chart for your README
[](https://hysenlabs.com/projects/toptal-chewy)Was this useful?