Artificial Intelligence

Embedding Model Migration: The Full Reindex Runbook

Rows of server racks with network cabling in a data center, representing a production vector database undergoing a full reindexing migration
cnrdmroglu

An embedding model migration is always a full reindex: every vector you serve must be regenerated with the new model before you cut traffic over, because embeddings produced by different models cannot be compared in the same vector space. Qdrant supports two zero downtime paths — a blue-green switch between two collections, or an in-place named-vector migration on deployments new enough to allow it. Pinecone offers no in-place path at all: index configuration is fixed at creation, so a model change means a new index and a complete backfill. Everything below is the runbook: pick the path, keep writes consistent during the backfill, verify coverage and retrieval quality, then flip traffic while a rollback still exists.

The trigger is rarely optional. Model deprecations, price changes and provider consolidation all force embedding swaps eventually, and the failure mode of doing it half-way is silent: a query embedded with the new model against documents embedded with the old one returns plausible-looking but wrong results. Treat the swap as a data engineering migration with a verification gate, not a configuration change.

Why old vectors cannot stay

Vector search compares positions in one coordinate system. Every embedding model produces its own: the same sentence lands somewhere different under a different encoder, and similarity scores computed across mixed embeddings are meaningless. Qdrant’s migration guide is blunt about the consequence: switching models requires re-embedding all vectors in your collection, which can take time. There is no supported adapter, no projection trick you should trust in production, and no way to patch half a corpus and keep ranking sane.

The first prerequisite is access to the original text. Re-embedding requires the source documents — either from your primary database or from the payloads stored alongside the vectors. If you kept only the vectors and discarded the source, the migration is impossible until the corpus is rebuilt, which is the strongest argument for storing chunk text in the payload from day one.

Two Qdrant migration paths

Qdrant gives you two options, and the choice follows from how the collection was created. A blue-green migration works with any collection: create a second collection sized for the new model, enable dual writes, scroll through the old collection re-embedding each point into the new one, then flip the alias and retire the old collection. The alternative is an in-place named-vector migration: adding a new named vector field to an existing collection requires version 1.18 or later, and the collection must already have been created with named vectors.

The named-vector path is a schema-only add followed by per-point vector updates: you add the new model as an additional named vector, dual-write both embeddings, run a background scroll that fills the new vector on each existing point, then switch the using parameter in your queries and delete the old vector when you are satisfied. Rollback is trivial because the old vector stays in place until you remove it explicitly. The trade-offs:

StrategyApplies toRollbackMain cost
Blue-green, two collectionsAny Qdrant collectionFlip the alias backDuplicated payloads and double storage during the overlap
Named-vector field addQdrant 1.18+ collections already using named vectorsKeep the old vector, switch using backExtra vector storage per point in a single collection
New index plus backfillPinecone, or any provider with immutable index configurationKeep the old index until cutover is verifiedA full second index and full re-embedding spend

Dual writes and backfill

Both Qdrant paths share the same operational core. First, deploy a second writer — or extend the existing update service — so every incoming upsert is embedded with both models and written to both targets; skipping this guarantees divergence between the re-embedded and live halves of the corpus. Second, run the backfill as a background scroll over existing points, batching embedding calls and resuming from the last offset after failures. During the backfill, searches and new inserts can continue while updates and deletes to existing points are paused; Qdrant’s guide flags the same constraint for the blue-green variant, where deletes and partial updates either stop for the migration window or need dedicated reconciliation logic.

Cost and throughput planning belongs in this phase, not after it. The backfill re-embeds the entire corpus inside a bounded window, so project the embedding API spend before starting. If the corpus feeds an LLM pipeline, review prompt caching costs across Claude, Bedrock and Azure before assuming the re-embedding bill is trivial. For the worker fleet, the queue-depth autoscaling pattern in our full KEDA setup scales the scroll honestly: workers follow the remaining backlog instead of over-provisioning the whole window.

The Pinecone constraint

Pinecone removes the choice entirely. Pinecone resolves and fixes the model, dimension, and metric at index creation, and the embedding configuration cannot be changed on an existing index — so a model change is always “create a new index, backfill everything, repoint clients”. Document-schema indexes are equally rigid: once created, their fields cannot be added, removed, or modified, and the documented remedy is deleting the index and creating a new one.

Hosted embedding adds a second, quieter trap: token truncation. Each model embeds only its first N tokens — 507 for multilingual-e5-large, 2,048 for llama-text-embed-v2, and 512 by default for pinecone-sparse-english-v0 — and longer values are silently truncated by default. If your chunks exceed the new model’s window, the migration completes while quietly degrading recall on long documents. Re-chunk before backfilling, and prefer rejecting over-length values during the backfill instead of truncating, so the failure is loud instead of invisible.

Cutover checklist

Work top to bottom, and do not skip the verification step.

  1. Locate or store the source text for every point — no source, no migration.
  2. Create the target (new collection, new named vector, or new index) sized for the new model’s dimension and metric.
  3. Enable dual writes for all new and updated documents before starting the backfill.
  4. Pause point-level updates and deletes, or implement reconciliation for them, across the backfill window.
  5. Backfill in batches with checkpointing, and verify that the count of points still missing the new embedding reaches zero.
  6. Compare retrieval quality between old and new embeddings on a held-out query set before touching traffic.
  7. Switch query traffic — alias flip or using parameter — then resume updates and deletes with dual writes still enabled.
  8. Keep the old target warm for one full business cycle, then delete it and drop dual writes.

Sources

Keep exploring