FlashRank: A CPU-Only Reranker for Retrieval Pipelines
Lite & Super-fast re-ranking for your search & retrieval pipelines. Supports SoTA Listwise and Pairwise reranking based on LLMs and cross-encoders and more. Created by Prithivi Da, open for PRs & Collaborations.
At a glance
- What is it?
- FlashRank is a Python library that adds a reranking stage to existing search and RAG pipelines using small cross-encoders or LLM-based listwise models. Its main trade-off is that it ships no torch or transformers dependency, which keeps the footprint tiny but caps the pairwise models at 512 tokens.
- Who is it for?
- Adopt FlashRank if you already have a retriever and want a reranking stage that runs on CPU inside a small deployment, and if your passages fit the 512-token cross-encoder limit or you are willing to install the listwise extra for the 8192-token LLM rerankers. Do not adopt it if you need sliding-window handling of more than 20 passages with rank_zephyr, or if your workload is dominated by long documents that no supported model can see whole.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 67 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The retrieval stage FlashRank inserts itself into
Most retrieval pipelines are two-stage whether or not anyone planned it that way. A first stage does something cheap and approximate: BM25, a vector index, or a hybrid of both. It returns a candidate list, usually tens of items, ranked by a score that was never meant to be a final answer. FlashRank occupies the second stage. It takes a query and a list of passages and returns the same passages with a new ordering and a score attached to each. The README describes it as a way to re-rank search results before feeding them into an LLM, which places it squarely in RAG and search front ends rather than in indexing or storage. The intended user is someone who already has a retriever and does not want to rebuild it. You pass in whatever your vector database or lexical search returned, and FlashRank changes the order. The library does not retrieve anything itself.
Two families of reranker, with different token ceilings
FlashRank supports two kinds of reranker and the distinction matters more than any other detail in the README. The first is pairwise or pointwise, built on cross-encoders, with a maximum of 512 tokens. The second is listwise and LLM-based, with a maximum of 8192 tokens. A cross-encoder reads the query and one passage together and produces a relevance score, so the number of forward passes scales with the number of candidates. The listwise models instead see a set of passages at once and produce an ordering, which is why the context window is so much larger and why the model sizes jump from megabytes to gigabytes. The model table lists seven entries. ms-marco-TinyBERT-L-2-v2 is the default at roughly 4MB. ms-marco-MiniLM-L-12-v2 is described as the best cross-encoder reranker at about 34MB. rank-T5-flan is called the best non cross-encoder reranker at about 110MB. ms-marco-MultiBERT-L-12 covers 100+ languages at about 150MB, with an explicit warning in the code sample not to use it for English. ce-esci-MiniLM-L12-v2 was fine-tuned on the Amazon ESCI dataset, which the README notes is unusual because most models are fine-tuned on MS MARCO Bing queries. rank_zephyr_7b_v1_full is a 4-bit quantised GGUF at roughly 4GB. miniReranker_arabic_v1 is described as the only dedicated Arabic reranker.
The no-torch constraint and what it buys
The README states plainly that no Torch or Transformers is needed and that the library runs on CPU. That is the design decision the rest of the project follows from. A default model of about 4MB and a dependency set without the usual deep learning stack means shorter cold starts and smaller deployment artifacts, which the README frames in cost terms: serverless platforms such as Lambda bill by memory and time per invocation, so a smaller package and a shorter startup both show up on the bill. The README also gives a rule for reasoning about latency: rerank speed is a function of the number of tokens in the passages, the query, and the model depth in layers. That is a useful mental model because it tells you the two knobs you control are passage length and model choice. It also means the pairwise ceiling of 512 tokens is not just a hard limit, it is a performance boundary. A longer passage costs more even when it still fits. The README adds that non-chalantly setting max_length to 512 for short passages will negatively affect response time, so the parameter is a tuning target rather than a safety margin.
Installation and the listwise extra
The base install is pip install flashrank, which the README labels as the lightweight pairwise path. If you want the LLM-based listwise rerankers, the command is pip install flashrank[listwise]. That extra exists because the listwise models pull in a much heavier runtime, and the split lets a deployment that only needs a 4MB cross-encoder avoid carrying it. Once installed, the entry points are Ranker and RerankRequest, imported from flashrank. The Ranker constructor takes model_name, cache_dir and max_length. The README shows a default and several named variants: Ranker(max_length=128) for the nano model, Ranker(model_name="ms-marco-MiniLM-L-12-v2", cache_dir="/opt") for the small model, Ranker(model_name="rank-T5-flan", cache_dir="/opt") for the medium zero-shot option, Ranker(model_name="ms-marco-MultiBERT-L-12", cache_dir="/opt") for multilingual work, and Ranker(model_name="rank_zephyr_7b_v1_full", max_length=1024) for the listwise model. The README notes that metadata on each passage is optional and that the id field can be your database ids from the retrieval stage or simple numeric indices, which is what makes it practical to map reranked results back to records you already hold.
Setting max_length is the whole tuning exercise
The README devotes a section to this and it is the most concrete operational guidance in the repository. The rule is that max_length must be large enough to hold your longest passage plus the query. The worked example: if your longest passage is about 100 tokens and the query about 16, the pair is 116, so max_length = 128 is enough once you leave room for reserved tokens such as [CLS] and [SEP]. The README suggests using a tokenizer library such as OpenAI tiktoken to estimate token density if per-token performance matters to you. It then warns in the other direction: setting a longer max_length like 512 for smaller passages will hurt response time. So the parameter is not a ceiling you set high and forget, it is a value you derive from your own corpus. This is the kind of instruction that is easy to skip and expensive to skip, because the failure is silent. A too-small max_length truncates, and a too-large one adds latency to every call without changing any ranking.
Where the listwise path runs out of room
The README carries an explicit limitation for rank_zephyr_7b_v1_full: the current integration supports a maximum of 20 passages in one pass, and sliding window logic is yet to be added. That is a real constraint on the listwise route. If your retriever returns 50 candidates, you either cut to 20 before reranking or you implement the windowing yourself outside the library. The README does not describe how to do the latter. A second limitation follows from the cross-encoder ceiling. Pairwise models cap at 512 tokens, and the README does not describe any chunking or passage-splitting strategy, so a long document that exceeds that budget has to be handled upstream. Third, the multilingual model comes with a warning not to use it for English, which means the language coverage is a per-model property rather than a library-wide one, and picking the wrong model for your corpus is a silent quality loss rather than an error. The README also states that detailed benchmarking is TBD and that the timing image is illustrative of the example rather than a general benchmark, so there is no published comparison table to lean on when choosing between the 4MB and 34MB models.
How this differs from running a cross-encoder yourself
The obvious alternative is sentence-transformers, which ships cross-encoder models and a CrossEncoder class you can call directly. The difference is the dependency graph and the deployment shape, not the ranking concept. sentence-transformers brings PyTorch and the transformers stack, which is what makes GPU execution and the wider model zoo available. FlashRank strips that out and runs on CPU, which is why the default model is 4MB rather than the tens or hundreds of megabytes typical of a full stack, and why the README's cost argument is about serverless invocation billing. If you need a model that is not in FlashRank's seven-entry table, or you want to fine-tune on your own data, sentence-transformers is the broader tool and FlashRank will not help you. If you want a reranking stage that fits in a Lambda memory limit and starts quickly, the trade is that you accept the smaller model list and the 512-token cross-encoder ceiling. The other practical alternative is to skip reranking entirely and rely on a better first-stage retriever, which is cheaper but leaves the ordering at the mercy of an approximate score.
Licence, releases and what to verify before adopting
FlashRank is Apache-2.0, which permits commercial use and modification with the usual attribution and notice requirements, and it includes a patent grant. That covers the library. It does not automatically settle the terms of the individual model weights, which come from different owners. The README thanks the model owners, and each entry links to a separate model card on Hugging Face, so the licence of the weights you actually download is a question for that model card and not for the repository licence. The release history is modest: 0.2.9 in November 2024 for minor fixes, 0.2.4 in April 2024 adding LLM-based listwise rerankers, and 0.1.64 in December 2023 adding Rank T5 support. The repository is not archived, and the README lists InRanker as a roadmap item. The upgrade surface is small because the public API is two classes and a handful of constructor arguments, so a version bump is unlikely to require code changes unless the model names or the max_length semantics shift. The real maintenance cost sits elsewhere: model weights are downloaded and cached under cache_dir, so you own cache invalidation, and if you pin a model you should verify that the model card still resolves. Before adopting, run your own longest query and passage through tiktoken, set max_length from that number, and check the model card for the language and domain you actually serve. If your candidate lists routinely exceed 20 passages and you want the listwise model, the sliding window logic is not in the library yet, and that gap should decide the question before anything else does.
Editorial conclusion
Adopt FlashRank if you already have a retriever and want a reranking stage that runs on CPU inside a small deployment, and if your passages fit the 512-token cross-encoder limit or you are willing to install the listwise extra for the 8192-token LLM rerankers. Do not adopt it if you need sliding-window handling of more than 20 passages with rank_zephyr, or if your workload is dominated by long documents that no supported model can see whole. Before committing, verify the actual token count of your longest query plus passage pair with tiktoken, set max_length to just above that number, and confirm that the model you pick is the one whose model card matches your language and domain.
Community notes