Handbooks  /  Cross-Encoder vs Bi-Encoder
AI~9 min readComparison
Head to Head

Cross-encoder vs bi-encoder: retrieve fast, or rank well?

Bi-EncodervsCross-Encoder

Both turn text into relevance, but they meet the query and the document at different moments — and that timing is everything. One lets you precompute and search millions of documents in milliseconds; the other reads a query and a document together for a far sharper judgment it can only make a few dozen times per query.

01

The one distinction that decides everything

A bi-encoder passes the query and each document through the model separately, turning each into its own vector; relevance is just the similarity between two independent vectors. Because a document’s vector doesn’t depend on the query, you can precompute all document vectors offline and, at query time, encode only the query and search the index. A cross-encoder feeds the query and a document through the model together, in one pass, and outputs a single relevance score — the two texts attend to each other directly, which is far more accurate, but the score exists only for that specific pair and can’t be precomputed.

→ The rule

Separate encoding (bi-encoder) buys scale: precompute once, search millions fast. Joint encoding (cross-encoder) buys accuracy: the model sees both texts at once — but must run per query–document pair, so it can’t scan a whole corpus.

02

Head to head

DimensionBi-EncoderCross-Encoder
EncodingQuery and doc encoded separatelyQuery and doc encoded together
Doc vectors precomputed?Yes — offline, onceNo — there is no standalone doc vector
Query-time cost1 query encode + fast vector search1 model pass per candidate
Scales toMillions–billions of documentsTens–hundreds of candidates
AccuracyGoodHigher — direct query–doc attention
RoleFirst-stage retrievalSecond-stage reranking
IndexANN (HNSW / IVF) over vectorsNone — runs on the shortlist
03

When to use each

Reach for a bi-encoder

  • Retrieving from a large corpus (thousands to billions of docs)
  • You need millisecond latency at query time
  • Document embeddings can be computed offline and indexed
  • The first stage of a RAG or search pipeline
  • Powering nearest-neighbor recommendations or dedup

Reach for a cross-encoder

  • Reranking a small shortlist for maximum precision
  • The top-k from retrieval must be ordered accurately
  • You can afford a model pass per candidate (tens, not millions)
  • Subtle relevance matters — the query and doc interact
  • Final ranking before showing results or feeding an LLM
04

The answer is "retrieve with one, rerank with the other"

You don’t choose — you stage them. The standard production pattern is retrieve-then-rerank: a bi-encoder retrieves a broad shortlist (say the top 100) from the whole corpus in milliseconds, then a cross-encoder rescoring reorders just those 100 into the final top 10. The bi-encoder does the impossible-at-scale part (scanning everything); the cross-encoder does the impossible-at-scale-but-cheap-on-100 part (reading each candidate carefully). You get the bi-encoder’s reach and most of the cross-encoder’s accuracy, for the cost of ~100 extra model passes per query.

→ The cheap default

Start with bi-encoder retrieval alone — it’s often good enough. Add a cross-encoder reranker when you can measure that the right answer is being retrieved but ranked too low for the top few results (or the LLM’s context) to see it.

05

Why you can’t just cross-encode everything

If cross-encoders are more accurate, why not use one for the whole search? Arithmetic. A cross-encoder produces a score only for a specific query–document pair, so ranking a corpus of one million documents against one query would require one million model forward passes — per query. That’s seconds to minutes of GPU time for a single search, which no interactive system can afford. The bi-encoder sidesteps this entirely: every document is encoded once, offline, into a vector; at query time you encode just the query and let an approximate-nearest-neighbor index find the closest vectors in milliseconds, never touching the model per document.

The cross-encoder’s accuracy comes from the same thing that makes it unscalable — the query and document attending to each other inside the model. You can’t precompute that interaction, because it doesn’t exist until the query arrives. So the two aren’t really competitors: the bi-encoder makes the search possible, and the cross-encoder makes the top of it sharp.

→ The trade you’re actually making

Bi-encoder trades a little accuracy for the ability to precompute and search at scale. Cross-encoder trades scalability for query–document interaction. Reranking is how you buy back the accuracy on just the few candidates that matter.

06

A worked scenario: semantic search over 10M documents

You’re building search over 10 million support articles. Encoding all 10M with a cross-encoder per query is a non-starter — that’s 10M passes for one search. So you embed all 10M documents once with a bi-encoder and store the vectors in an ANN index. A query comes in; you encode it once and the index returns the top 100 candidates in a few milliseconds. Good — but the true best answer might be sitting at rank 40, because separate encoding missed a subtle interaction.

Now a cross-encoder rescoring reads the query together with each of those 100 candidates — 100 model passes, entirely affordable — and reorders them, pulling that rank-40 answer up to the top 3 where the user (or an LLM building an answer) will actually see it. Same two models, staged: retrieve broad and fast, then rerank narrow and sharp.

→ The pattern generalizes

Whenever you must find a few great items in a huge set: use a cheap, precomputable scorer to shortlist, then an expensive, accurate scorer to rank the shortlist. Bi-encoder then cross-encoder is that pattern for text.

Frequently asked

Quick answers

What's the difference between a bi-encoder and a cross-encoder?

A bi-encoder encodes the query and each document separately into vectors, so document vectors can be precomputed and searched at scale, but it never sees the two texts together. A cross-encoder feeds the query and a document through the model together for a much more accurate relevance score, but must run once per query-document pair, so it cannot scan a whole corpus. Bi-encoders retrieve; cross-encoders rerank.

Which is more accurate?

The cross-encoder, because the query and document attend to each other directly inside the model instead of being compressed into separate vectors first. That interaction is exactly what a bi-encoder gives up in exchange for the ability to precompute document embeddings and search millions of them quickly.

Why not use a cross-encoder for the whole search?

Because it produces a score only for a specific pair, ranking a million-document corpus would need a million model passes per query — far too slow for interactive search. A bi-encoder encodes each document once offline, so query time is a single query encode plus a fast nearest-neighbor lookup.

What is retrieve-then-rerank?

The standard two-stage pattern: a bi-encoder retrieves a broad shortlist (say top 100) from the whole corpus in milliseconds, then a cross-encoder rescoring reorders just those candidates into the final ranking. You get the bi-encoder’s scale and most of the cross-encoder’s accuracy for the cost of a few dozen extra model passes.

Cross-Encoder vs Bi-Encoder · Vibe Engines · 2026
Finished this one? 0 / 139 Handbooks done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

Cite this page

Reference it in your work, paper or an AI's context window.

APASingh, S. (2026). Cross-Encoder vs Bi-Encoder. Vibe Engines. https://vibeengines.com/handbook/cross-encoder-vs-bi-encoder
MLASingh, Saurabh. “Cross-Encoder vs Bi-Encoder.” Vibe Engines, 2026, vibeengines.com/handbook/cross-encoder-vs-bi-encoder.
BibTeX
@online{vibeengines-cross-encoder-vs-bi-encoder,
  author       = {Singh, Saurabh},
  title        = {Cross-Encoder vs Bi-Encoder},
  year         = {2026},
  organization = {Vibe Engines},
  url          = {https://vibeengines.com/handbook/cross-encoder-vs-bi-encoder}
}