Federated Search Across Multiple Algolia Indices: Architecture, Merging, and Pitfalls
Learn how to query multiple Algolia indices in one request, merge heterogeneous results, and keep InstantSearch UI sections independent while avoiding common pitfalls.
11 Dec 2025, 09:04 UTC

The problem: one search box, many data types
Teams often need a single search experience that returns products, help articles, and category pages at once. Algolia does not merge indices automatically; each index stays isolated for ranking, rules, and analytics. The engineering decision is how to query them together, merge the hits, and keep the UI coherent without exploding operation costs or bundle size.
Index architecture and query routing
Algolia’s multipleQueries endpoint (POST /1/indexes/*/queries) lets you send up to 100 sub‑queries in one HTTP request. Each sub‑query targets a distinct index and returns its own hits array. This saves round‑trips compared to firing separate client‑side requests, but the response still contains separate hit lists—you must merge them yourself.
POST /1/indexes/*/queries
Content-Type: application/json
{
"requests": [
{ "indexName": "products", "params": "query=wireless&hitsPerPage=5" },
{ "indexName": "articles", "params": "query=wireless&hitsPerPage=5" }
]
}
The response looks like:
{
"results": [
{ "index": "products", "hits": [...], "nbHits": 120 },
{ "index": "articles", "hits": [...], "nbHits": 45 }
]
}
Because each index can have its own custom ranking (e.g., products by popularity, articles by date), raw scores are not directly comparable. Normalise or weight scores before interleaving.
Result merging strategies
- Interleaving by normalised score – map each index’s ranking to a 0‑1 range, apply a weight (e.g., products 0.7, articles 0.3), then sort the combined array.
- Section grouping – keep hits grouped by index, render a header (“Products”, “Articles”) and paginate each section independently.
- Unified ranking via
transformItems– in InstantSearch connectors, receive the per‑index hit arrays, merge them, and return a single array for theHitswidget.
Example transformItems for interleaving:
const mergeHits = (items) => {
const [products, articles] = items; // each is { hits, ... }
const normalize = (hits, maxScore) => hits.map(h => ({
...h,
_mergedScore: (h._rankingInfo?.nbTypos ?? 0) / maxScore // simplistic example
}));
const all = [...normalize(products.hits, 100), ...normalize(articles.hits, 50)];
return all.sort((a,b) => b._mergedScore - a._mergedScore);
};
// In a custom connector
connectHits(({ hits, ...rest }) => (
<Hits hits={mergeHits(hits)} {...rest} /
));
UI integration with InstantSearch
The <Index indexName="products" indexId="products"> widget creates a scoped search state. Wrap each index in its own Index component but share a single <SearchBox> at the top level. This gives you:
- Unified query input.
- Independent pagination, faceting, and routing per section (thanks to distinct
indexId). - Shared
searchStatefor URL sync if you omitindexId.
<InstantSearch indexName="products" searchClient={client}>
<SearchBox />
<Index indexName="products" indexId="products">
<Hits />
<Pagination />
</Index>
<Index indexName="articles" indexId="articles">
<Hits />
<Pagination />
</Index>
</InstantSearch>
Remember: each Index loads its own connector logic. If bundle size matters, code‑split the section components.
Trade‑offs and limitations
- Operation cost – a single
multipleQueriesrequest counts as one operation but returns hits for every index. LargehitsPerPageon many indices can spike usage. - Ranking inconsistency – custom ranking, typo tolerance, and
ignorePluralsare per‑index. Merged results can feel “jumpy” if settings diverge. - Rules & synonyms – merchandising (pinning, hiding) must be duplicated across indices; a rule in
productsnever affectsarticles. - Analytics attribution – click events require the originating
indexName. Forgetting it pollutes per‑index A/B test data. - Geo & distinct – geo‑search and
distinctde‑duplication operate per index. Post‑merge distance sorting or cross‑index de‑duplication must be implemented client‑side.
Verification checklist (run in staging)
- Create two test indices (
products,articles) with distinct custom ranking. - Use the dashboard Multi‑Query Explorer to send a federated query; confirm separate
hitsarrays. - Build a minimal InstantSearch page with two
Indexwidgets sharing aSearchBox; verify independent pagination. - Fire
insightsclick events withindexNameset; check the Analytics dashboard for correct attribution. - Add a Rule to pin a product; ensure it appears only in the products section.
- Enable
_geolocon products, run a federated query witharoundLatLng; confirm products respect distance while articles return unscored.
Closing action
Start with the multipleQueries endpoint for low‑latency fan‑out, then implement a lightweight transformItems merger that normalises scores using a configurable weight map. Keep each index’s ranking, rules, and analytics isolated, and only merge at the presentation layer. This gives you a single search box, predictable costs, and the flexibility to evolve each data source independently.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.