algolia alternative open source

Algolia Alternative: Open Source Search Options for Developers in 2026

Algolia's pricing is structured around search requests and records. At 100,000 searches per month with 50,000 records, you're looking at $50-$200/month depending on the plan tier. That's before overages. If a campaign drives a traffic spike, your bill moves unpredictably. The alternatives below give you the same — or better — search quality without per-request billing.

Why developers leave Algolia

The core complaint isn't the product — Algolia's relevance engine is genuinely good. The complaint is the pricing model. At $0.50 per 1,000 additional search requests (Grow plan) or $1.75 per 1,000 (Grow Plus), costs scale directly with traffic. A documentation site getting 500,000 monthly searches pays $250-$875/month for search alone. That's a meaningful line item for something users consider table stakes.

The second complaint is overages. Algolia's pricing page states that exceeding committed usage incurs overage charges, but the overage rate isn't presented clearly until you exceed your tier. Developers who've been surprised by a $400 bill after a Hacker News front page hit are the loudest advocates for the alternatives below.

Cost reference: Algolia Grow includes 10,000 search requests/month free. Beyond that: $0.50/1K (Grow) or $1.75/1K (Grow Plus). A site with 200,000 monthly searches costs $95-$332/month on Grow or Grow Plus respectively.

The six alternatives at a glance

ToolPricingSelf-hostSemantic searchBest for
TypesenseOSS free; cloud ~$43/moEasy (single binary)Yes (ML models)Server-side, real-time updates
MeilisearchOSS free; cloud $20/moEasy (single binary)Yes (hybrid)Server-side, developer-friendly
OramaOSS free; cloud enterpriseJavaScript, no binaryYes (vector)JavaScript-native, edge deployment
PagefindFree, open sourceNo server neededNo (full-text only)Static sites, keyword search
Fuse.jsFree, open sourceNo server neededNo (fuzzy matching)Small in-memory datasets
altor-vecFree, MIT licensedNo server neededYes (HNSW in browser)Static sites, semantic search, privacy

Typesense

Typesense is the closest direct Algolia replacement for teams that need a self-managed search server. It's a single Go binary with no external dependencies — you run it, point your indexing script at it, and query it. The API surface is intentionally similar to Algolia's, which makes migration straightforward.

Typesense Cloud starts at roughly $43/month for the smallest instance (shared, 0.5 vCPU, 512MB RAM). At that tier you're paying per hour of compute, not per query — which immediately removes the overage anxiety. The self-hosted version is free indefinitely with no license restrictions.

For semantic search, Typesense supports embedding generation via built-in ML models or external providers (OpenAI, Cohere). The caveat: built-in ML embedding at index time can be slow — a few thousand records can take several minutes. For large corpora, pre-generating embeddings and sending them as vectors is faster.

Honest limitation: Typesense requires a running server. That's a reasonable operational cost for most teams, but it's not zero. You need to handle availability, upgrades, and backups.

Meilisearch

Meilisearch positions itself as "the search engine you can understand" — the relevance model is transparent and tweakable. Like Typesense, it's a single binary with an HTTP API. The developer experience is excellent: the dashboard is clean, the indexing API is simple, and the documentation is among the best in this space.

Meilisearch Cloud starts at $20/month — cheaper than Typesense Cloud and significantly cheaper than Algolia at any meaningful traffic volume. The self-hosted version is free. Hybrid search (keyword + vector) is supported, with the tradeoff that you supply pre-generated embeddings rather than Meilisearch computing them.

Honest limitation: Meilisearch's relevance tuning options are more limited than Algolia's. If you need fine-grained merchandising rules, custom ranking formulas, or AI-driven re-ranking, Algolia still has an edge. For standard search-over-documents use cases, Meilisearch is excellent.

Orama

Orama (@orama/orama on npm) is a JavaScript-native search engine — it runs in the browser, in Node.js, on Cloudflare Workers, and on any JS runtime. Unlike the server-based options above, you import it as a library and it manages an in-memory index. 3 million npm downloads per month indicates real adoption.

Orama supports vector search via its @orama/plugin-embeddings package, which can call external embedding APIs or use a local model. The cloud offering (Orama Cloud) is enterprise-priced with no public tier list — you contact sales.

Honest limitation: For large corpora, keeping the full index in JavaScript memory gets expensive. Orama is best suited for bounded datasets — a few thousand documents at most before you hit browser memory constraints. For anything larger, you need a server or a static index approach.

Pagefind

Pagefind takes a fundamentally different approach: it runs a crawler against your built HTML output, chunks the content, and generates a static index that loads incrementally in the browser. The browser only downloads the chunks relevant to the current query, which keeps initial payload small even for large sites.

Pagefind powers search on MDN, the Godot documentation, and thousands of static sites. It's genuinely excellent at what it does — fast, accurate keyword search with zero server requirements. The npm package installs a CLI that you run as a postbuild step.

Honest limitation: Pagefind is full-text keyword search. A query like "how to improve recall at k" won't match a page that talks about "increasing top-k precision" — the words don't overlap. If your users phrase queries differently from your content's exact wording, Pagefind will miss results that a semantic search engine would catch.

Fuse.js

Fuse.js is a fuzzy string matching library — it finds approximate matches based on character overlap. With 10.5 million weekly npm downloads, it's the default choice for developers adding basic search to small datasets. You initialize it with an array of objects, define which keys to search, and call fuse.search(query).

For small, bounded datasets where users type exact terms — names, product codes, city names — Fuse.js is a reasonable choice. It adds 5KB to your bundle and has zero configuration overhead.

Honest limitation: Fuse.js doesn't understand meaning. Searching "inexpensive" won't match "affordable" or "budget-friendly" because the character overlap is minimal. For natural language queries over paragraph-length content, Fuse.js produces poor results regardless of threshold tuning.

altor-vec

altor-vec is a Rust-compiled WASM library that runs HNSW (Hierarchical Navigable Small World) vector search entirely in the browser. You build a float vector index offline, ship it as a static file, load it in the browser, and query it with no network roundtrip and no server.

The library is 54KB gzipped. Query latency at 10,000 vectors (384 dimensions) is under 1ms p95 on a modern laptop. Because retrieval is local, latency doesn't depend on network conditions.

The indexing workflow: at build time, run a Node script that reads your content, generates embeddings (using Transformers.js locally or an embedding API), and writes a binary index file to your /public directory. At runtime, the browser loads that file once and searches it on every query.

Install: npm install altor-vec

When altor-vec is the right choice

When altor-vec is not the right choice

Migration from Algolia to altor-vec

For a documentation or blog site, the migration is straightforward. The key shift is moving from Algolia's push-based indexing (you call their API when content changes) to a pull-based build step (you run a script at deploy time).

// scripts/build-index.mjs
import fs from 'node:fs/promises';
import { glob } from 'glob';
import { pipeline } from '@huggingface/transformers';
import init, { WasmSearchEngine } from 'altor-vec';

await init();

const embed = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
const files = await glob('./content/**/*.md');
const vectors = [];
const metadata = [];

for (const file of files) {
  const text = await fs.readFile(file, 'utf8');
  const title = text.split('\n')[0].replace(/^#+\s*/, '');
  const body = text.slice(0, 1000); // first 1000 chars as excerpt
  const out = await embed(title + '\n' + body, { pooling: 'mean', normalize: true });
  vectors.push(...Array.from(out.data));
  metadata.push({ file, title, excerpt: body.slice(0, 200) });
}

const dim = 384;
const flat = new Float32Array(vectors);
const engine = WasmSearchEngine.from_vectors(flat, dim, 16, 200, 50);

await fs.writeFile('./public/search-index.bin', Buffer.from(engine.to_bytes()));
await fs.writeFile('./public/search-metadata.json', JSON.stringify(metadata));
console.log(`Indexed ${metadata.length} documents`);

Add this to your build pipeline:

// package.json
{
  "scripts": {
    "build": "your-static-site-build-command",
    "postbuild": "node scripts/build-index.mjs"
  }
}

On the frontend, replace your Algolia search component with a fetch + WASM call:

import init, { WasmSearchEngine } from 'altor-vec';
import { pipeline } from '@huggingface/transformers';

let engine, metadata, embedder;

async function initSearch() {
  await init();
  const [indexBuf, meta] = await Promise.all([
    fetch('/search-index.bin').then(r => r.arrayBuffer()),
    fetch('/search-metadata.json').then(r => r.json()),
  ]);
  engine = new WasmSearchEngine(new Uint8Array(indexBuf));
  metadata = meta;
  embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
}

async function search(query, topK = 5) {
  const out = await embedder(query, { pooling: 'mean', normalize: true });
  const hits = JSON.parse(engine.search(new Float32Array(out.data), topK));
  return hits.map(([id, distance]) => ({
    ...metadata[id],
    score: 1 - distance,
  }));
}

Choosing the right alternative

The decision mostly comes down to two questions: do you have a server, and does your content update continuously?

If you already run backend infrastructure and your content changes frequently, Meilisearch (self-hosted) or Typesense (cloud) are the practical choices. Both have flat-rate pricing, good relevance out of the box, and straightforward migration paths from Algolia.

If you're running a static site — a documentation portal, a technical blog, a marketing site — and your content updates on deploy cycles, altor-vec or Pagefind are worth considering seriously. Pagefind for keyword accuracy on exact terminology; altor-vec for natural language queries and semantic intent matching.

If your dataset is small enough to fit in memory and users type exact terms, Fuse.js might already be sufficient — don't add complexity without measuring whether you actually have a relevance problem first.

FAQ

What is the best free Algolia alternative?

For self-hosted search with a server: Meilisearch or Typesense. Both are fully open source with no search volume limits. For static sites with no server: altor-vec (semantic) or Pagefind (keyword). All four are MIT or Apache licensed with no usage-based pricing.

Does altor-vec support real-time indexing?

No. altor-vec builds a static binary index at deploy time. It suits content that updates on build/deploy cycles — documentation, blogs, product catalogs that update weekly. For search over user-generated content or continuously changing data, use a server-side solution.

How does altor-vec bundle size compare to Algolia InstantSearch?

altor-vec WASM is 54KB gzipped. Algolia's InstantSearch.js core is approximately 100-150KB gzipped before any UI widgets. The index file itself is separate — for 10,000 documents at 384 dimensions it's roughly 15MB, which you load once and cache aggressively.

Try client-side semantic search: npm install altor-vec · GitHub