npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rerank-lite

v0.1.2

Published

Lightweight retrieval reranker using cross-encoder scoring

Readme

rerank-lite

Lightweight retrieval reranker for JavaScript and TypeScript -- zero dependencies, three scoring modes, one API.

npm version npm downloads license node


Description

rerank-lite takes a query and a list of candidate documents from a first-stage retriever (vector search, BM25, or fusion) and reorders them by relevance. It is the second stage of a two-stage retrieval pipeline: stage one retrieves candidates quickly with approximate methods, stage two reranks them precisely for the final result set.

The package ships three scoring modes that share a single rerank() API and return the same RerankResult[] output:

  • Heuristic -- BM25 + TF-IDF + position-based scoring with zero external dependencies. Works immediately after install.
  • LLM -- Delegates scoring to a caller-supplied judge function. Bring any LLM provider (OpenAI, Anthropic, local Ollama, etc.).
  • Hybrid -- A 50/50 blend of heuristic and LLM scores for balanced accuracy and cost.

All scores are normalized to the [0, 1] range. The output is ready to pass to a context packer, fusion ranker, or directly into an LLM prompt.


Installation

npm install rerank-lite

Requires Node.js 18 or later.


Quick Start

import { rerank } from 'rerank-lite'

const documents = [
  { id: 'doc-0', text: 'Machine learning model training with neural networks' },
  { id: 'doc-1', text: 'Quick sort algorithm and data structures' },
  { id: 'doc-2', text: 'Deep learning transformer architecture for NLP' },
]

const results = await rerank('machine learning neural network', documents)

for (const result of results) {
  console.log(`[rank ${result.newRank}] ${result.document.id} -- score: ${result.score.toFixed(4)}`)
}

Features

  • Three scoring modes -- heuristic, LLM-as-judge, and hybrid, all behind one function signature.
  • Zero runtime dependencies -- heuristic mode is pure TypeScript with no external packages.
  • BM25 scoring -- corpus-aware term frequency / inverse document frequency with configurable k1 and b parameters, normalized via sigmoid.
  • TF-IDF cosine similarity -- builds TF-IDF vectors for the query and each document, scores by cosine similarity against the corpus.
  • Position bias -- original retrieval rank feeds into the composite score, preserving signal from the first-stage retriever.
  • Configurable weights -- tune the relative contribution of BM25, TF-IDF, and position scoring.
  • Top-K and minimum score filtering -- limit output to the top K results and filter below a score threshold.
  • Pluggable LLM judge -- pass any async function that scores a (query, document) pair. No SDK lock-in.
  • Factory pattern -- createReranker() returns a preconfigured instance for repeated use across many queries.
  • Full TypeScript support -- ships with declaration files and source maps. All types are exported.

API Reference

rerank(query, documents, options?)

Reranks an array of documents against a query. Returns a Promise<RerankResult[]> sorted by relevance score descending.

import { rerank } from 'rerank-lite'

const results = await rerank('machine learning', documents, {
  mode: 'heuristic',
  topK: 10,
  minScore: 0.3,
  weights: { bm25: 0.5, tfidf: 0.3, position: 0.2 },
})

Parameters:

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | query | string | Yes | The search query to rank documents against. | | documents | Document[] | Yes | Array of candidate documents from a first-stage retriever. | | options | RerankOptions | No | Configuration for scoring mode, filtering, and weights. |

Returns: Promise<RerankResult[]> -- results sorted by score descending, with newRank assigned as 0-based indices.

Behavior with empty input: Returns an empty array when documents is empty.


createReranker(config?)

Factory that returns a configured Reranker instance. Preset options are applied to every rerank() call; per-call options override the preset.

import { createReranker } from 'rerank-lite'

const reranker = createReranker({
  mode: 'heuristic',
  topK: 10,
  weights: { bm25: 0.6, tfidf: 0.3, position: 0.1 },
})

const results = await reranker.rerank('first query', docs)

// Override topK for this call only
const top3 = await reranker.rerank('second query', docs, { topK: 3 })

Parameters:

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | config | RerankerConfig | No | Default configuration applied to all calls. |

Returns: Reranker -- an object with a rerank() method and a read-only config property.


Types

Document

Represents a candidate document to be scored.

interface Document {
  id: string                        // Unique identifier for the document
  text: string                      // The text content to score against the query
  score?: number                    // Optional original retrieval score
  metadata?: Record<string, unknown> // Optional pass-through metadata
}

RerankResult

A scored and ranked document returned by rerank().

interface RerankResult {
  document: Document    // The original document object, including metadata
  score: number         // Relevance score in [0, 1]
  originalRank: number  // 0-based index in the input array
  newRank: number       // 0-based rank after reranking (0 = most relevant)
  explanation?: string  // Optional debug information
}

RerankOptions

Options for a single rerank() call.

interface RerankOptions {
  topK?: number           // Return only the top K results (default: all)
  minScore?: number       // Filter out results with a score below this threshold
  mode?: RerankMode       // Scoring mode (default: 'heuristic')
  judgeFn?: JudgeFn       // Required when mode is 'llm' or 'hybrid'
  weights?: ScoringWeights // Custom weights for heuristic scoring components
}

RerankMode

type RerankMode = 'heuristic' | 'llm' | 'hybrid'

| Mode | Description | |------|-------------| | heuristic | BM25 + TF-IDF + position weighted scoring. Zero dependencies. Default. | | llm | Delegates scoring entirely to the caller-supplied judgeFn. | | hybrid | 50/50 blend of heuristic scores and judgeFn scores. |

JudgeFn

The function signature for LLM-as-judge scoring.

type JudgeFn = (query: string, document: string) => Promise<number>

Must return a numeric relevance score. Called once per document when mode is llm or hybrid.

ScoringWeights

Weights for the three heuristic scoring signals. All are optional and default to the values shown.

interface ScoringWeights {
  bm25?: number      // Default: 0.5
  tfidf?: number     // Default: 0.3
  position?: number  // Default: 0.2
}

RerankerConfig

Configuration for the createReranker() factory. Same shape as RerankOptions.

interface RerankerConfig {
  mode?: RerankMode
  topK?: number
  minScore?: number
  judgeFn?: JudgeFn
  weights?: ScoringWeights
}

Reranker

The instance returned by createReranker().

interface Reranker {
  rerank(query: string, documents: Document[], options?: RerankOptions): Promise<RerankResult[]>
  readonly config: RerankerConfig
}

Configuration

Scoring Weights

The heuristic composite score is computed as:

score = (bm25_weight * bm25_score) + (tfidf_weight * tfidf_score) + (position_weight * position_score)

Default weights:

| Signal | Default Weight | Description | |--------|---------------|-------------| | bm25 | 0.5 | BM25 term frequency / inverse document frequency score, normalized to [0, 1] via sigmoid. | | tfidf | 0.3 | TF-IDF cosine similarity between query and document vectors. | | position | 0.2 | Position bias: 1 - (originalRank / totalDocuments). Preserves signal from the first-stage retriever. |

Override weights to tune for your retrieval domain:

// Favor lexical match, ignore original ordering
const results = await rerank('exact keyword query', docs, {
  weights: { bm25: 0.7, tfidf: 0.3, position: 0.0 },
})

// Trust the first-stage retriever, use reranking as a tiebreaker
const results = await rerank('semantic query', docs, {
  weights: { bm25: 0.2, tfidf: 0.2, position: 0.6 },
})

BM25 Parameters

The BM25 scorer accepts standard tuning parameters k1 (term frequency saturation, default 1.5) and b (document length normalization, default 0.75). These are set internally and follow the Robertson/Zaragoza BM25 formulation.


Error Handling

rerank() handles edge cases gracefully without throwing:

  • Empty documents array -- returns an empty array [].
  • No matching terms -- all documents receive a baseline score (sigmoid of zero for BM25, zero for TF-IDF). Documents are still ranked by position bias.
  • Empty query or document text -- TF-IDF returns 0 for empty strings. BM25 returns the sigmoid baseline (0.5).

When using llm or hybrid mode, errors from the judgeFn propagate as-is. Wrap your judge function with try/catch if you need graceful degradation:

const safejudgeFn = async (query: string, doc: string): Promise<number> => {
  try {
    return await yourLLMScorer(query, doc)
  } catch {
    return 0 // Fallback score on failure
  }
}

const results = await rerank('query', docs, { mode: 'llm', judgeFn: safejudgeFn })

Advanced Usage

LLM-as-Judge Mode

Pass any async function that returns a relevance score. The function is called once per document.

import { rerank } from 'rerank-lite'
import OpenAI from 'openai'

const openai = new OpenAI()

const judgeFn = async (query: string, document: string): Promise<number> => {
  const response = await openai.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [
      {
        role: 'user',
        content: `Rate the relevance of this document to the query on a scale from 0 to 1.\nQuery: ${query}\nDocument: ${document}\nRespond with only a number between 0 and 1.`,
      },
    ],
  })
  return parseFloat(response.choices[0].message.content ?? '0')
}

const results = await rerank('machine learning', docs, { mode: 'llm', judgeFn })

Hybrid Mode

Combines heuristic scoring with LLM judgment. The final score is a 50/50 blend:

hybrid_score = 0.5 * heuristic_score + 0.5 * llm_score
const results = await rerank('machine learning', docs, {
  mode: 'hybrid',
  judgeFn,
  weights: { bm25: 0.5, tfidf: 0.3, position: 0.2 }, // Applies to heuristic half
})

RAG Pipeline Integration

Use reranking as stage two after vector search or BM25 retrieval:

// Stage 1: Retrieve candidates from your vector database
const candidates = await vectorDB.query(embedding, { topK: 50 })

// Stage 2: Rerank for precision
const reranked = await rerank(query, candidates, { topK: 10, minScore: 0.4 })

// Stage 3: Pass to LLM context
const context = reranked.map(r => r.document.text).join('\n\n')

Reusable Reranker Instance

For applications that rerank many queries with the same configuration:

import { createReranker } from 'rerank-lite'

const reranker = createReranker({
  mode: 'heuristic',
  topK: 10,
  minScore: 0.3,
  weights: { bm25: 0.6, tfidf: 0.25, position: 0.15 },
})

// Use across multiple queries
const results1 = await reranker.rerank('first query', docs1)
const results2 = await reranker.rerank('second query', docs2)

// Override per-call when needed
const results3 = await reranker.rerank('third query', docs3, { topK: 5 })

Filtering with minScore and topK

minScore is applied first, then topK limits the output:

// Return at most 5 results, all with score >= 0.5
const results = await rerank('query', docs, { topK: 5, minScore: 0.5 })

TypeScript

rerank-lite is written in TypeScript and ships with declaration files (.d.ts) and source maps. All types are exported from the package entry point:

import {
  rerank,
  createReranker,
  type Document,
  type RerankResult,
  type RerankOptions,
  type RerankMode,
  type JudgeFn,
  type ScoringWeights,
  type RerankerConfig,
  type Reranker,
} from 'rerank-lite'

The package targets ES2022 and emits CommonJS modules. It is compatible with both require() and bundlers that resolve the exports field.


License

MIT