Search Integration for MedusaJS + Next.js + Sanity: Scoring, Ranking & Relevance
People who use site search convert at roughly two to three times the rate of people who only browse. That number shows up consistently across verticals and catalog sizes. It is not a curiosity. It is a signal that search users arrive with intent, and a store that understands their query earns the sale.
When search fails, the cost is not just a missed click. It is a trust collapse. A shopper who sees zero results for a product you actually carry, or irrelevant noise for a straightforward query, will leave. They will not try a second search. They will try a different store.
In a headless commerce stack, search is harder than it looks. Product truth lives in MedusaJS. Content truth lives in Sanity. Pricing and inventory shift by the minute. There is no single database to query, no monolith handing you results for free.
What you need is a read-optimized projection (the search index), a deliberate ranking model, and event-driven ingestion that keeps everything current. This guide covers each layer in a way that is engine-agnostic, so the thinking applies no matter which search provider you end up choosing.
The Architecture
Before evaluating any search product, draw the boundaries. Each system in the stack has a clear job, and the search index sits between them as a derived, disposable view.
MedusaJS: Commerce Source of Truth
MedusaJS owns products, variants, pricing tiers, inventory quantities, and collection memberships. Every fact about what you sell, how much it costs, and whether it is in stock originates here.
This data changes frequently. Flash sales update prices. Warehouse receipts update stock. New SKUs land daily. The search index must reflect these changes quickly, but Medusa itself is never queried directly by the search UI.
Sanity: Content Source of Truth
Sanity owns editorial material: buying guides, lookbooks, landing pages, category descriptions, brand stories, and any structured content that supports the shopping experience.
This content changes less frequently than commerce data, but it matters for search. A well-written buying guide that ranks for "best running shoes for flat feet" can pull organic traffic and convert through internal search simultaneously.
The Search Index: Read-Optimized Projection
The index is not a database. It is a denormalized, precomputed projection optimized for retrieval speed and relevance scoring. It does not own data. It receives documents derived from Medusa and Sanity, structured for the search engine's query model.
Because the index is derived, it is disposable. You can tear it down and rebuild it at any time from the sources of truth. That freedom lets you experiment with schemas, swap engines, or recover from corruption without fear of data loss.
Next.js: Orchestration and UX
Next.js hosts the API routes that proxy search queries, renders the results page, drives autocomplete, and handles server-side concerns like geo-routing, A/B tests on ranking, or personalized boosts.
The key constraint: Next.js reads from the search index. It never writes to Medusa or Sanity on behalf of the search system. Data flows one way into the index, and queries flow one way out through Next.js to the browser.
Index Design That Supports Ranking
The quality of your search results is determined before a single query runs. It is determined by how you structure documents in the index.
Product Document Schema
Every product document needs three categories of fields, each serving a different purpose in the ranking process.
**Text relevance fields** are what the engine matches against the query: product title, description body, brand name, SKU, variant labels (color, size, material), and any concatenated tags. Weight these fields differently at query time (more on that in the scoring section).
**Facet fields** are structured, filterable attributes: category path, brand, price (as a numeric), color, size, material, and any custom Medusa attributes. These must be indexed as filterable/facetable, not just searchable.
**Ranking signal fields** carry numeric or boolean values that influence ordering: units sold in the last 30 days, days since publish, current stock quantity, average review rating, margin tier, and promotional flags. Store these as dedicated numeric fields so they can feed into scoring formulas.
Do not flatten everything into a single text blob. The whole point of structured index documents is to give the ranking model distinct signals to work with.
Content Document Schema
Sanity stores rich text as Portable Text, a JSON structure. Before indexing, convert it to plain text using the `toPlainText` utility available in most Sanity libraries.
A content document should include: the plain-text body, the title, the content type (guide, blog post, landing page), tags or categories, the canonical URL, a publication date, and optionally a relevance weight that lets you boost certain content types over others.
Content type is critical for ranking control. A comprehensive buying guide about "wireless headphones" should rank above a blog post that mentions headphones in passing. The content type field makes that distinction possible at query time.
Start Separate, Blend Later
Begin with separate product and content indices. The document schemas are different, the ranking rules are different, and debugging relevance issues is much easier when you know which index produced which result.
Blended results (showing a buying guide alongside product results) can be implemented later in the Next.js API route by querying both indices, normalizing scores, and interleaving results. This approach gives you explicit control over how many content cards appear, and where.
Scoring and Ranking
Ranking is not one algorithm. It is a stack of scoring layers, each adding a different dimension of relevance. Think of it as a series of lenses that progressively sharpen the result set.
Layer 1: Lexical Relevance
This is the base: how well does the document text match the query text?
**Field weighting** is the most impactful lever. A match in the product title should count far more than a match in the description. A reasonable starting configuration: title at weight 5, brand at 3, SKU at 2, description at 1. These are not magic numbers. They are starting points you will tune.
**Phrase proximity boosts** reward results where query terms appear near each other and in order. "Blue running shoes" should favor a title of "Blue Running Shoes" over "Shoes for Running, Available in Blue." Most engines support phrase or proximity boosting as a configurable parameter.
**Typo tolerance** is non-negotiable for ecommerce. Customers misspell brand names, invent abbreviations, and type on small screens. An edit distance of 1 for words under 5 characters and 2 for longer words is a sensible default. Monitor precision after enabling: too much tolerance introduces irrelevant matches.
Layer 2: Query Understanding
Transforming the query before it reaches the index can dramatically improve result quality.
**Normalization** means lowercasing, stripping accents, and collapsing whitespace. Every query should pass through this step.
**SKU tokenization** handles product code searches. If a customer types "NKE-AF1-WHT," the analyzer needs to match "NKEAF1WHT" or "NKE AF1 WHT" in the index. Configure a custom tokenizer for SKU fields that strips delimiters and normalizes casing.
**Synonym management** closes vocabulary gaps. "Sneakers" and "trainers" should resolve to the same concept. "Couch" and "sofa" as well. Build an initial synonym list from your catalog, then expand it monthly using zero-result query reports.
**Navigational redirects** catch queries that are not searches at all. When someone types "return policy," "shipping," or "track order," they want a specific page. Detect these patterns and redirect instead of showing search results. This is a small investment with large satisfaction returns.
Layer 3: Business Scoring
Here is where search becomes a revenue instrument.
**Stock-aware scoring** penalizes low-inventory or out-of-stock items. You probably do not want to hide them entirely (a customer might want to see the item and opt into a restock alert), but they should not hold top positions. Apply a multiplier: in-stock gets 1.0, low-stock gets 0.7, out-of-stock gets 0.3. Tune from there.
**Popularity scoring** boosts items that are selling well. Use units sold over a rolling window (the last 14 or 30 days) rather than all-time totals. This keeps seasonal items and new arrivals from being buried by legacy best-sellers.
**Freshness scoring** applies a time-decay curve so newer products receive a mild boost. This matters for stores with frequent drops (fashion, electronics, seasonal goods). A gentle logarithmic decay works better than a sharp linear one.
**Controlled promotions** allow merchandisers to pin specific items to the top of specific queries. A new product launch, a seasonal campaign, or a margin-priority push can override organic ranking. Use this with discipline. Over-pinning erodes the credibility of search results.
The final score typically looks like a weighted sum: `final = textScore * 0.55 + popularity * 0.2 + freshness * 0.1 + stockModifier * 0.1 + promotionBoost * 0.05`. You will change these weights over time. The point is that each signal has an explicit, tunable contribution.
Optional: Hybrid and Semantic Scoring
Vector-based search captures meaning beyond keywords. A query like "something cozy for winter evenings" can match a cashmere throw even if no field contains those exact terms.
But vector search adds complexity: embedding generation, vector storage, approximate nearest-neighbor tuning, and a blending strategy to merge vector scores with lexical scores.
Before investing, look at your query logs. If 90% of searches are product names, brands, or categories, lexical search with synonyms will cover you. If you see a meaningful volume of conceptual or natural-language queries, hybrid search is worth piloting.
Roll it out alongside lexical, not as a replacement. Blend scores with a tunable weight. Keep a lexical-only fallback for queries where the vector model returns low-confidence results. Measure conversion impact before committing.
Facets, Filters, and Autocomplete
Ranking determines the order. Facets and autocomplete determine whether the user even needs to scroll.
Facets That Reflect How Customers Think
Facets should mirror the customer's decision-making process, not your internal taxonomy. If customers decide by use case ("running," "trail," "casual"), expose a use-case facet even if Medusa stores it as a custom attribute.
Limit the results page to 8 to 10 facet groups. More than that creates decision fatigue. Prioritize the facets with the highest engagement rates and hide the rest behind an "All Filters" expansion.
Dynamic facet counts (showing "Nike (23)" and updating to "Nike (7)" after a price filter is applied) are essential. They set expectations and prevent dead-end clicks. Choose an engine that computes these counts efficiently at query time.
Autocomplete Done Right
Autocomplete is the first thing a customer interacts with. Latency above 150ms feels sluggish. Irrelevant suggestions feel broken.
A complete autocomplete experience includes three tiers of suggestions. First, **query completions**: the user types "run" and sees "running shoes," "running shorts," "running watch." These come from a curated list of popular and valid queries. Second, **product suggestions**: direct matches with a thumbnail, title, and price, letting the user jump straight to a product detail page. Third, **category shortcuts**: typing "hea" surfaces a "Shop Headphones" link that drops the user into a filtered collection page.
On the Next.js side, debounce input by 150 to 250 milliseconds. Cache responses for popular prefixes at the edge or in a short-TTL store. Fan out to multiple suggestion endpoints if needed, but return a single merged payload to the client.
Ingestion Strategy
A perfect ranking model on stale data delivers bad results. Ingestion is the connective tissue between your sources of truth and the search index.
Event-Driven Updates from Medusa
MedusaJS emits lifecycle events for entities. The ones that affect search include product creation and updates, variant changes, price list modifications, inventory adjustments, and collection membership changes.
For each relevant event, the ingestion handler should: fetch the entity's current state from the Medusa API, transform it into the index document schema (including all ranking signal fields), and upsert the document in the search index using a partial update endpoint.
Partial updates are important. Reindexing an entire document because the stock level changed by one unit is wasteful. Most search engines support updating specific fields without resubmitting the full document.
Webhook-Driven Updates from Sanity
Sanity supports GROQ-powered webhooks that fire on document publish, unpublish, and delete events. Configure these for every document type included in the content index.
On publish, fetch the document, convert Portable Text fields to plain text, and upsert the content document.
On unpublish or delete, remove the document from the content index.
Watch for slug changes. If a guide's URL path changes and the index still holds the old slug, search results will link to a 404. Treat slug updates as document upserts with the corrected URL field.
Taxonomy renames (changing a category label or merging tags) may affect many documents at once. Handle these with a targeted batch reindex of all documents referencing the changed term.
Full Reindex as a Safety Net
Some changes require rebuilding the index from scratch: schema migrations, ranking formula overhauls, analyzer changes, or recovery after an ingestion failure that left the index in an inconsistent state.
Build a reindex script that reads every product from the Medusa API (paginated) and every searchable document from the Sanity API, transforms them, and writes them to a new index. Once the new index is built and verified, swap the search alias so queries cut over with zero downtime.
Run a scheduled full reindex (nightly or weekly) even when incremental ingestion is healthy. It catches edge cases: events lost to transient failures, race conditions, or schema drift. Think of it as reconciliation.
Measurement Loop
Search optimization is not a project with a finish line. It is a feedback loop. Ship, measure, adjust, repeat.
Metrics That Matter
**Zero-result rate**: the share of queries that return nothing. Aim for under 5%. Above 10% means your index or synonyms have significant gaps.
**Search CTR**: the percentage of searches where the user clicks at least one result. Low CTR on a high-volume query means the results are not matching intent.
**Add-to-cart after search**: measures commercial intent captured. Compare this to add-to-cart rates from non-search browsing to see whether search is pulling its weight.
**Conversion rate after search**: users who searched and then purchased, divided by total searchers. This is the number that justifies continued investment in search quality.
Turning Data into Action
Export your top 50 zero-result queries weekly. For each, decide: is it a synonym gap (add the synonym), a catalog gap (you do not carry that item), or a spelling issue (widen typo tolerance for that term)?
Pull the top 20 queries by volume that have below-average CTR. Review the result page for each. Are the top results relevant? If not, adjust field weights, add a synonym, or apply a business rule.
Track indexing lag: the time between an event in Medusa or Sanity and the corresponding document update in the search index. Set an alert threshold. Two minutes is a reasonable target. If lag exceeds that, investigate the ingestion path.
Build a lightweight weekly dashboard. It does not need to be complex. A spreadsheet with the four core metrics, trended over time, is enough to guide decisions.
How to Choose a Search Engine
Because this guide is engine-agnostic, here are the evaluation criteria that should drive your selection.
**Facet and filter performance.** Test with your actual catalog size. Some engines degrade when computing faceted counts across hundreds of thousands of documents with many attribute combinations.
**Relevance tuning controls.** You need field weighting, custom scoring formulas, synonym dictionaries, and typo tolerance configuration. If the engine only offers a black-box relevance algorithm with no knobs, you will hit a ceiling quickly.
**Operational model.** Hosted services remove infrastructure burden but introduce vendor dependency and usage-based costs. Self-managed engines (built on open-source cores) offer full control but require cluster management expertise.
**Scaling and cost predictability.** Understand how pricing scales with document count, query volume, and index size. Model your projected usage at 12 and 24 months and compare total cost of ownership across candidates.
**Hybrid and semantic readiness.** If your roadmap includes vector search, prioritize engines that support it natively today or have a published plan for it. Migrating to a different engine later is costly and disruptive.
**Built-in analytics.** Some engines provide query analytics (popular queries, zero-result reports, CTR tracking) out of the box. Others require you to build that instrumentation yourself. Factor in the engineering time for each path.
There is no universally best engine. There is only the best fit given your catalog, traffic, team capabilities, and budget.
How Adeptive Delivers This
We have designed and implemented search systems across headless commerce stacks, and the architecture in this guide reflects patterns we use in production.
Our engagements typically span four workstreams. Architecture design establishes the integration boundaries between Medusa, Sanity, the search index, and Next.js. Index schema development produces document structures that carry the right text fields, facet attributes, and ranking signals. Ingestion engineering builds the event-driven sync layer (plus full-reindex tooling) that keeps the index fresh and consistent. Relevance tuning and analytics sets up scoring formulas, synonym lists, and the measurement dashboard, then iterates on all of it based on real user data.
We do not push a specific search engine. We help you evaluate options against your requirements and implement whichever one fits.
Book a search relevance audit and get a concrete implementation plan.
If you are building search from scratch or inheriting a setup that is underperforming, we can help you turn search into the conversion lever it should be.
See how we approach ecommerce search projects.
Frequently Asked Questions
Should I use a hosted search engine or self-host?
For most teams, hosted is the right starting point. It eliminates operational overhead (provisioning, scaling, patching, monitoring) and lets you focus on relevance and UX. Self-hosting makes sense when you face strict data-residency constraints, when hosted pricing becomes prohibitive at your document or query volume, or when you have in-house infrastructure engineers with search experience. Start hosted. Migrate later only if you have a concrete reason.
Should out-of-stock products be hidden or downranked?
Downranking is usually the better choice. Hiding items entirely confuses customers who know the product exists, perhaps from a previous visit or an ad. Push out-of-stock items to lower positions and display a clear "Out of Stock" label with an optional restock notification. If an item has been unavailable for more than 30 days and there is no restock date, consider removing it from the index to keep results clean.
How do I handle multi-locale and multi-currency search?
Create locale-specific indices (or use a locale field within a shared index) so that each locale gets language-appropriate text analysis: stemming, stop-word removal, and character normalization tuned to that language. For currency, either index all relevant currency values per product or store the base price and apply conversion at query time. Facet ranges (price sliders, price buckets) must reflect the user's active currency. MedusaJS supports multi-region configurations natively, so the commerce data layer already accommodates this.
How do I keep prices and inventory accurate in the search index?
Listen to Medusa's inventory-level and price-update events and push changes to the index in near real time. For inventory, update the stock quantity field and recalculate any stock-based ranking modifier. For prices, update the price field and regenerate any derived facet buckets (like price ranges). Monitor indexing lag and set an alert if it exceeds your tolerance (a few minutes is typical). Run a nightly or weekly full reindex as reconciliation to catch any events that were dropped.
When does semantic or vector search make sense for ecommerce?
It makes sense when a meaningful share of your queries are conceptual or conversational. "Gift for a teenager who likes hiking" or "minimalist desk setup" are examples where keyword matching falls short. If your analytics show that most queries are product names, brands, or category terms, lexical search with solid synonym coverage handles them well. Add semantic search when you have data proving a gap, and when your team can manage the operational complexity of embedding models and vector indices.
What is a typical implementation timeline?
For a MedusaJS, Sanity, and Next.js stack, expect 4 to 8 weeks for a production-grade implementation. The first week covers architecture decisions and engine selection. Weeks two and three focus on index schema design and the ingestion layer. Weeks three through five deliver the Next.js search UI, autocomplete, and facet filtering. Weeks five through seven are for ranking configuration and business scoring rules. Week eight sets up the analytics dashboard and runs the first optimization cycle. Teams with prior search experience tend toward the shorter end. Teams new to search infrastructure should plan for the longer end.
How often should ranking rules be revisited?
Monthly, at minimum. Review your search analytics: check zero-result trends, identify low-CTR high-volume queries, and compare conversion rates against previous periods. Adjust synonyms, field weights, and business scoring in response to what the data shows. Catalog changes (new categories, seasonal rotations, major promotions) should trigger an immediate review. The best search experiences are built through continuous, data-informed iteration.
---
Search is not a feature you add at the end of a build. It is a system that directly shapes how customers find products and whether they convert. In a headless architecture with multiple data sources, getting it right takes deliberate design, layered scoring, reliable ingestion, and a commitment to ongoing measurement.