Implementing and Verifying Algolia Synonyms for Consistent Search Results
Add an Algolia synonym, wait for the async task, and verify with paired canonical/variant queries — plus precision pitfalls and a clean rollback path.
28 Mar 2026, 15:42 UTC

The problem: equivalent terms, inconsistent hits
Users type "sofa" while your catalog says "couch", or they search "sneakers" when your records say "trainers". Without synonyms, Algolia matches on the literal tokens in your records, so a perfectly valid query returns few or no results. The fix is a synonym: a saved rule that tells the engine two or more terms should be treated as equivalent. The useful takeaway is that synonyms are cheap to add but easy to get subtly wrong — they apply asynchronously, interact with ranking settings, and a broad synonym can quietly merge concepts you wanted separate. This guide covers adding one synonym, verifying it actually changed results, and rolling it back safely.
Before you start
- An Algolia application and an existing index containing records you can test against.
- An Admin API key (or a key with settings/synonyms write permission). Never embed this in browser or mobile code — run synonym writes from a backend, script, or CI job.
- A search-only API key for running verification queries, matching what your frontend uses.
- A small, reviewed list of equivalent terms. Start with two or three pairs, not a bulk import.
Method names below follow the v4 JavaScript client (algoliasearch). If you use a different SDK version or language, confirm the exact method signatures in that client's documentation — synonym APIs have changed shape between major client versions.
Step 1: Save the synonym
Run this from a Node.js backend or script where the admin key is available as an environment variable:
import { algoliasearch } from "algoliasearch";
const client = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_ADMIN_KEY
);
const { taskID } = await client.saveSynonym({
indexName: "products",
objectID: "syn-sofa-couch",
synonymHit: {
objectID: "syn-sofa-couch",
type: "synonym",
synonyms: ["sofa", "couch", "settee"]
}
});
// Synonyms apply asynchronously — wait before testing.
await client.waitForTask({ indexName: "products", taskID });Notes on the payload:
objectIDmust be unique per synonym. Use a readable, namespaced ID so you can find and delete it later.type: "synonym"is the regular multi-way type: any listed term matches any other. Algolia also supports one-way synonyms (type: "oneWaySynonym"with aninputterm), placeholders, and alternative corrections — pick the regular type unless you specifically need asymmetric behavior.
Risk: the write itself is low-risk and reversible, but saveSynonym overwrites any existing synonym with the same objectID. Check for collisions if IDs are generated.
Step 2: Confirm the synonym was stored as intended
Before judging search behavior, fetch the object back and compare it to what you meant to send:
const saved = await client.getSynonym({
indexName: "products",
objectID: "syn-sofa-couch"
});
console.log(saved.type, saved.synonyms);You should see synonym and the exact term list. If the terms differ, overwrite with a corrected payload rather than layering a second synonym. You can also confirm in the Algolia dashboard under the index's Synonyms section, and check that no indexing task is still pending — searching before the task finishes is the most common reason a correct synonym looks broken.
Step 3: Compare canonical vs. variant queries
Run two searches with identical filters, pagination, and query parameters — one for the canonical term, one for the variant. Use the search-only key and the same parameters your production frontend sends, because distinct, typo tolerance, optional words, and filters can mask or amplify synonym effects:
const searchClient = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_SEARCH_KEY
);
const params = { indexName: "products", hitsPerPage: 10 };
const a = await searchClient.searchSingleIndex({ ...params, searchParams: { query: "couch" } });
const b = await searchClient.searchSingleIndex({ ...params, searchParams: { query: "sofa" } });
console.log(a.hits.map(h => h.objectID));
console.log(b.hits.map(h => h.objectID));What to look for:
- The variant query now returns the records that previously only matched the canonical term.
- Ordering may differ slightly — synonyms do not guarantee identical ranking, only equivalent matching. Judge whether differences are material for your use case.
- No obviously irrelevant records appear. If they do, your term list may be too broad (see below).
Precision pitfalls to check
Multi-way synonyms are symmetric and transitive in effect: if you declare "sofa = couch = settee", every term expands to all others. Two common failure modes:
- Merged concepts. "Pants" and "trousers" are equivalent in one region, but "pants" also means underwear in another. If a term is ambiguous, prefer a one-way synonym or leave it out.
- Over-expansion. Adding hypernyms ("shoe" as a synonym of "sneaker") floods results. Keep synonym sets to true equivalents and inspect borderline queries from real search logs before promoting.
Rollback: delete and re-baseline
Because saving a synonym changes index behavior, keep a rollback path ready. Deleting by objectID restores prior behavior:
const { taskID } = await client.deleteSynonym({
indexName: "products",
objectID: "syn-sofa-couch"
});
await client.waitForTask({ indexName: "products", taskID });After the task completes, re-run the control query ("sofa") and confirm results return to the pre-synonym baseline. If they don't, check for other synonyms or rules affecting the same terms.
Production rollout recommendation
Apply the synonym to a staging or replica index with representative data first, run the comparison queries there, and only then write it to production. Synonym changes are instant to write but affect every user query, so treat them like a ranking configuration change: small batches, verified one at a time.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.