Overview
This guide walks you through building a custom search provider for Spree. By the end, you’ll have a fully functional search integration that:- Powers product search, filtering, sorting, and faceted navigation
- Handles multi-locale and multi-currency indexing automatically
- Integrates with the Store API without any frontend changes
- Supports background indexing and bulk reindex
Spree ships with a built-in Meilisearch provider. If Meilisearch fits your needs, you don’t need to build a custom provider — just configure it.
Architecture
Step 1: Create the Provider Class
Create a class that inherits fromSpree::SearchProvider::Base and implements search_and_filter:
app/models/my_app/search_provider/typesense.rb
indexing_required? returning true tells the SearchIndexable concern to enqueue background jobs when products are created, updated, or destroyed.
Step 2: Implement search_and_filter
This is the core method. It receives a base AR scope (already filtered for security) and must return a SearchResult:
app/models/my_app/search_provider/typesense.rb
Step 3: Implement Indexing
Products are indexed as one document per market × locale combination. TheProductPresenter handles this automatically:
app/models/my_app/search_provider/typesense.rb
ProductPresenter returns an array of documents. For a store with US (USD/English) and EU (EUR/German+French) markets, one product produces 3 documents — each with flat name, price, locale, currency fields.
Step 4: Implement Bulk Reindex
Usepreload_associations_lazily to avoid N+1 queries:
app/models/my_app/search_provider/typesense.rb
Use
flat_map (not map) because ProductPresenter#call returns an array of documents per product.Step 5: Register the Provider
config/initializers/spree.rb
Provider Contract Reference
SearchResult
ProductPresenter
Indexing Lifecycle
TheSpree::SearchIndexable concern on Product provides:
Background jobs (
IndexJob, RemoveJob) fire on after_commit when indexing_required? is true.
Important: Prefixed IDs
Always use prefixed IDs (ctg_abc, prod_xyz, optval_abc) when indexing. Never use raw database IDs — Spree supports UUID primary keys.
Related Documentation
- Search & Filtering — Store API search reference
- Meilisearch Integration — Built-in Meilisearch provider setup

