Index alias
A stable name (e.g. products-read) that points to a physical index, so you can rebuild a new index and repoint readers atomically with no client change.
An index alias is a nickname for a search or vector index. Your application always queries catalog-read; behind the scenes that name points at catalog-v7. When you rebuild the index (new embedding model, new chunking), you build catalog-v8 next to it, check it, then move the nickname in one step. Nobody redeploys, and rolling back is moving the nickname back. It is the mechanism behind Blue-green deployment for search.
A company's support phone number: the number on the website never changes, but the switchboard can route it to a new call centre overnight.
Querying the physical index name directly from one service 'just for now'. The swap moves every reader except that one, which keeps serving the old embeddings against new query vectors, or breaks when the old index is deleted.
Elasticsearch and OpenSearch support atomic multi-action _aliases requests (remove old, add new in one call), and an alias can have one is_write_index. Qdrant has collection aliases with atomic change_aliases operations; Milvus has alter_alias. Where the store lacks aliases (pgvector tables, some managed vector DBs), emulate one with a config row or flag that the query service reads, or a Postgres view swapped in a transaction. Keep separate read and write aliases: during a migration writes go to both physical indexes (via the consumer, see Dual-write) while reads move only when the new index is verified. Version physical names with the embedding model and chunker (catalog_e5l-1024_c512_v8) so nothing ever queries a mismatched model. Clients must not cache the resolved name; they always call the alias. Delete old physical indexes on a schedule, because forgotten v3–v6 indexes double storage bills.
Read alias + write alias per logical index; physical names encode embedding model, dimension, chunker and version; swaps via Elasticsearch/OpenSearch _aliases or Qdrant change_aliases; config-row emulation for pgvector; old index retained 7 days then deleted by a scheduled job.
An e-commerce catalog of 9M products moves from a 768-d to a 1024-d embedding. The team builds catalog_v8 (backfill 7 h), points the CDC consumer at both v7 and v8, runs shadow queries for 3 days (NDCG@10 0.71 → 0.76 on 2,000 judged queries), then swaps catalog-read with one _aliases call: remove catalog_v7, add catalog_v8. A filter bug on size facets appears an hour later; rollback is the reverse call, 400 ms. Fixed, re-swapped next day, v7 deleted after 7 days.
Any index I expect to rebuild sits behind read and write aliases from day one, with model and chunker versions in the physical name. Rebuilds become build, dual-write, shadow, swap, keep the old one a week. The follow-up: 'your vector DB has no aliases?' I'd hold the active index name in a config table the query service reads per request, which gives the same atomic swap.
Numbers worth knowing
- Alias swap time
- <1 ssingle atomic cluster-state update in Elasticsearch/OpenSearch
- Storage during migration
- ~2×both physical indexes live with dual-writes
- Rollback window
- 7 daysenough for quality feedback to surface on search changes
How to decide
| When | Do this |
|---|---|
| Rebuilding with a new embedding model or chunker | New physical index, alias swap; never in-place. |
| Store supports native aliases | Use them with atomic multi-action swaps. |
| Store lacks aliases (pgvector table) | Config row or view swapped in one transaction. |
| Per-tenant indexes | One alias per tenant so you can migrate tenants one at a time. |
Cost maths
Overlap storage: 9M × 1024 dims × 4 bytes = 37 GB raw float32 per index, plus HNSW overhead ~1.5× ≈ 55 GB; two copies for a week on managed storage at ~$0.10–0.25/GB-month is a few dollars. The bigger cost is forgetting: five stale versions of a 55 GB index on SSD-backed nodes can mean an extra data node (~$500–1,000/month) for nothing.
Operating it
- More than 2 physical versions alive per logical index
- Per-tenant indexes >1,000: automate alias management and migration waves
- Swaps done by hand in the console: script them with pre-swap checks (doc count, golden-set recall)
- Queries hitting physical (non-alias) index names: alert >0
- Physical index versions per logical index: alert >2
- Doc count and golden-set recall check before every swap: block if new < old by >0.5%
When it goes wrong
Search relevance on an internal wiki dropped sharply for one department's app only, two weeks after a successful migration.
Relevance complaints, then traces showing that app querying wiki_v5 while all others used wiki-read → v6.
That app had hardcoded the physical index name; it was now embedding queries with the new model and searching vectors from the old one.
Index-level permissions only allow reads through aliases; physical index names removed from app configs; a lint check for _v\d+ index names in code.
Sources
- Aliases — Elastic, 2025docs
- Collections (collection aliases) — Qdrant, 2025docs
Check yourself
Three questions. Every option is explained once you answer.