@mercurjs/core, modeled on Medusa’s pluggable-provider pattern (like the file and notification modules). The module owns a stable contract — index, remove, search — and delegates storage to exactly one active provider. Out of the box that provider is Orama: an in-process, in-memory index that needs zero external infrastructure.
Everything above the provider is provider-agnostic. Subscribers index and remove documents on product, offer, and seller events; the store route calls
search.search(query); boot reindexing is event-driven. Swapping Orama for Algolia or Meilisearch means changing one provider registration — no changes to subscribers, the store route, or your storefront.What gets indexed
Products and offers are searchable. Offers are indexed as per-offer documents — one hit per vendor listing — each carrying the offer’s scoped price, so search results price identically toGET /store/offers. Index updates are driven by subscribers on product, offer, and seller events; you never call index() from application code.
Searching from the storefront
The Store API exposes one endpoint:| Field | Description |
|---|---|
q | Search query (defaults to "" — browse mode) |
limit / offset | Pagination (limit 1–100, default 12) |
region_id, country_code, province | Pricing context — the provider projects the matching price onto each hit’s calculated_price |
filters | Passed straight to the active provider, which owns its shape |
hits, count, and facets.
The default provider: Orama
The bundledsearch-orama provider keeps the index in RAM inside the API process. That means:
- Zero setup — no accounts, keys, or services. Search works on a fresh project.
- Boot reindex — an in-memory index is empty after a restart, so the module emits a reindex event on application start and a subscriber rebuilds the index from the database.
In-memory search fits development and small-to-medium catalogs. For large catalogs or multi-instance deployments, use a persistent provider — the index then lives in the external service and the boot reindex is unnecessary.
Swapping in Algolia or Meilisearch
Ready-made provider integrations ship as blocks:| Provider | Hosting | Best for |
|---|---|---|
| Orama (default) | In-process | Zero-infra development and smaller catalogs |
| Algolia | Managed SaaS | Fastest setup, hosted relevance tuning |
| Meilisearch | Self-hosted or cloud | Full control, open source |
Writing your own provider
A provider extendsAbstractSearchProvider from @mercurjs/core and implements three methods:
Verify
- Start a fresh project and
POST /store/searchwith an emptyq— published products return without any search service configured (that’s Orama). - Publish a product and search for its title — it appears without a manual reindex (subscribers indexed it).
- Restart the API and search again — results still return (the boot reindex rebuilt the in-memory index).
FAQ
Can I run two providers at once, e.g. Orama locally and Algolia in production?
Can I run two providers at once, e.g. Orama locally and Algolia in production?
Only one provider is active at a time — the module has no multi-provider machinery. But because the provider is chosen by configuration, you can register different providers per environment (default Orama in development, Algolia in production) without touching any other code.
Do I ever need to trigger a reindex manually?
Do I ever need to trigger a reindex manually?
Normally no — subscribers keep the index current, and in-memory providers rebuild on boot. A manual full reindex is only interesting after bulk data changes outside normal flows (e.g. direct DB imports); persistent providers ignore the boot event entirely.
Why does each offer appear as its own search hit?
Why does each offer appear as its own search hit?
Because pricing and availability are per offer, not per product. One hit per vendor listing lets results carry the correct
calculated_price for each seller — the same numbers as GET /store/offers — instead of an ambiguous product-level price.Next steps
Offers
Why offers are indexed per seller with scoped prices.
Add a feature with a block
How provider blocks are installed and configured.