How to self-host a reranker

Production · ~10 min read ·

Hosted rerank APIs are convenient, but self-hosting gives you zero per-call cost, full data control, and predictable latency on your own GPU or CPU fleet. Here’s a practical path from a first CrossEncoder call to a production microservice.

When self-hosting wins

When you need multilingual quality with minimal ops, a hosted API like Cohere Rerank or Jina may still be cheaper all-in — see choose by scenario.

Pick a model

ModelSizeBest for
bge-reranker-base~278MCPU-friendly English default
bge-reranker-v2-m3~568MMultilingual when GPU is limited
Qwen3-Reranker-4B~4B2026 open SOTA pick (needs GPU)
mxbai-rerank-large-v1~435MStrong classic BEIR, Apache 2.0
jina-reranker-v3largeListwise long-context; or v2 pair-wise

Start with bge-reranker-base on CPU for prototyping. On GPU, A/B Qwen3-Reranker-4B against bge-v2-m3 or mxbai-large on your labelled set — do not assume leaderboard order transfers.

Quick start with sentence-transformers

pip install sentence-transformers torch

from sentence_transformers import CrossEncoder

model = CrossEncoder("BAAI/bge-reranker-base", max_length=512)

query = "How do I add reranking to RAG?"
docs = [
    "Retrieve 50–100 candidates, rerank with a cross-encoder, keep top 5.",
    "London is the capital of the United Kingdom.",
]

pairs = [(query, d) for d in docs]
scores = model.predict(pairs)  # higher = more relevant
ranked = sorted(zip(scores, docs), reverse=True)

Batch your pairs — scoring 50 documents in one predict() call is far faster than 50 separate forwards. Cap passage length at 512 tokens (model default) to avoid silent truncation.

Serving options

Embedded in your app

Load the model inside your FastAPI / Flask RAG service. Simplest for low QPS; scale replicas horizontally.

Dedicated rerank microservice

Expose POST /rerank with { query, documents[] }. Share one GPU across many app pods.

# Minimal FastAPI sketch
from fastapi import FastAPI
from sentence_transformers import CrossEncoder

app = FastAPI()
model = CrossEncoder("BAAI/bge-reranker-base")

@app.post("/rerank")
def rerank(body: dict):
    q, docs = body["query"], body["documents"]
    scores = model.predict([(q, d) for d in docs])
    order = sorted(range(len(docs)), key=lambda i: -scores[i])
    return {"results": [{"index": i, "score": float(scores[i])} for i in order]}

For ONNX export and C++ runtimes, see the model cards on Hugging Face. For browser-only experiments, try our in-browser demo with the xsmall ONNX builds.

Ops checklist

Prototype before you deploy

Paste your own query and passages in the browser demo — no server required.

Open the demo →

Keep reading