# Orama Comparison & Analysis

## Overview

This document compares [Orama](https://github.com/oramasearch/orama) (~10K+ stars, TypeScript) against our schema discovery search library. Orama is the closest TypeScript-native competitor to @coda/search — a full-text + vector + hybrid search engine that runs in-process with BM25 scoring, typo tolerance, and vector search in <2KB.

Orama is the strongest "could we just use this?" challenge for @coda/search.

**Last updated**: 2026-05-10

---

## How Orama works

Orama is an embeddable search engine built in TypeScript:

1. **Full-text search**: BM25+ scoring (improved BM25 variant), stemming in 30 languages, typo tolerance, exact match, field boosting, prefix search, auto-suggestions
2. **Vector search**: Cosine/dot-product similarity over float32 vectors
3. **Hybrid search**: Combined full-text + vector scoring with configurable mode (`fulltext`, `vector`, `hybrid`)
4. **Faceted search**: Field-level facets, filters, geosearch
5. **Plugins**: Embeddings generation, data persistence, analytics, secure proxying

### Orama's current state (May 2026)

- **~10K+ GitHub stars**, active development, TypeScript-first
- **Runs everywhere**: Node.js, Deno, browsers, edge runtimes (Cloudflare Workers, Vercel Edge)
- **Tiny bundle**: <2KB core engine
- **Plugin ecosystem**: `@orama/plugin-embeddings`, `@orama/plugin-data-persistence`, `@orama/plugin-analytics`
- **OramaCore**: Separate server-side product with full-stack features (answer engines, copilots)
- **Framework integrations**: Vitepress, Docusaurus, Astro

---

## How our system differs

| Aspect                   | Orama                               | @coda/search                                                                 |
| ------------------------ | ----------------------------------- | ---------------------------------------------------------------------------- |
| **Purpose**              | General-purpose search engine       | Schema discovery for AI agent tool selection                                 |
| **Corpus**               | Any JSON documents                  | Structured schema metadata (GraphQL types, Snowflake tables)                 |
| **BM25**                 | BM25+ with 30-language stemming     | BM25 with Porter stemming, camelCase splitting, prefix fallback              |
| **Vector search**        | Float32 cosine/dot-product          | HNSW with uint8 quantization (4x memory reduction)                           |
| **Hybrid search**        | BM25 + vector (simple mode toggle)  | 10-signal RRF fusion (BM25 + vector + glossary + graph + fuzzy signals)      |
| **Score fusion**         | Simple linear combination           | Reciprocal Rank Fusion (RRF) — rank-based, mathematically principled         |
| **Graph signals**        | None                                | 5 graph signals: degree, adamic-adar, betweenness, column-density, proximity |
| **Glossary expansion**   | None                                | Domain glossary with fuzzy matching + synonym expansion                      |
| **Fuzzy search**         | Typo tolerance (built-in)           | Edit-distance trie search via `FuzzyStage`                                   |
| **Schema awareness**     | None — treats all docs as flat JSON | FK inference, join path discovery, schema-graph-augmented results            |
| **Reranking**            | None                                | `RerankProvider` interface (cross-encoder pipeline stage)                    |
| **Lifecycle**            | Stateless (create, insert, search)  | State machine: CREATED→READY→DEGRADED→DESTROYED with two-phase embed         |
| **Incremental updates**  | Manual insert/update/remove         | `SchemaFetcher.diff()` → automatic incremental index updates                 |
| **Snapshot persistence** | Plugin-based persistence            | Versioned snapshots with content-hash keys + warm-start vector reuse         |
| **Observability**        | Plugin analytics                    | 28 typed event types, OTel-compatible envelope, per-query trace IDs          |
| **Evaluation**           | None built-in                       | NDCG=0.887, MRR=0.943, Recall@10=0.994; 189 golden queries; MRR guard        |
| **Bundle size**          | <2KB core                           | ~150KB (includes BM25, HNSW, trie, graph, signals)                           |
| **Runtime**              | Node.js, Deno, browsers, edge       | Node.js only (in-memory indexes require server runtime)                      |

### Why we didn't adopt Orama

1. **No graph signals** — Orama has no concept of a relationship graph. Our schema search relies heavily on FK inference, join path discovery, degree/betweenness/proximity signals, and graph-augmented results. These are fundamental to schema discovery.

2. **No glossary expansion** — Orama has no domain-aware query expansion. Our glossary system maps business terms ("royalties", "mechanical income") to schema identifiers without LLM calls.

3. **Simple fusion** — Orama's hybrid mode uses a simple linear combination of BM25 and vector scores. Our 10-signal RRF fusion is mathematically principled for heterogeneous signals and produces better NDCG in benchmarks.

4. **No lifecycle management** — Orama is stateless per index instance. No state machine, no two-phase initialization, no graceful degradation, no abort coordination.

5. **No evaluation framework** — No built-in benchmark suite, golden queries, or regression guards. We need formal retrieval quality metrics to prevent regressions.

---

## What we could adopt from Orama

### 1. 30-language stemming

Orama supports stemming in 30 languages. We use Porter stemming (English only). Low priority — our corpus is English schema metadata.

### 2. Browser/edge runtime support

Orama runs in browsers and edge runtimes. Our in-memory HNSW and graph indexes require a server, but the BM25 + trie components could theoretically run client-side. Low priority — no browser use case exists.

### 3. Plugin architecture for persistence

Orama uses plugins for persistence, analytics, and embeddings. Our `SnapshotPersistence` interface and `EmbeddingProvider` interface serve similar roles but without a formal plugin registry. Informational only — our interface-based DI is more flexible.

---

## Enterprise readiness comparison

| Dimension                | Orama                                  | @coda/search                                                              |
| ------------------------ | -------------------------------------- | ------------------------------------------------------------------------- |
| **Deployment model**     | Embeddable library or OramaCore server | Embeddable library, deployed as Fargate microservice                      |
| **State management**     | Stateless per index                    | Explicit state machine (CREATED→READY→DEGRADED→DESTROYED)                 |
| **Graceful degradation** | None — search fails or succeeds        | Two-phase init, keyword-only fallback, per-stage fallback                 |
| **Observability**        | Plugin analytics                       | 28 typed event types, OTel-compatible, per-query trace IDs                |
| **Incremental updates**  | Manual insert/update/remove            | Automatic diff-based refresh via SchemaFetcher                            |
| **Snapshot/recovery**    | Plugin-based persistence               | Versioned S3 snapshots with 3-dimensional cache keys                      |
| **Evaluation**           | None built-in                          | NDCG/MRR/Recall benchmarks, 189 golden queries, MRR regression guard      |
| **Test coverage**        | Community tests                        | ~1,386 unit tests, zero LLM dependency                                    |
| **Schema awareness**     | None                                   | FK inference, graph signals, join path discovery, graph-augmented results |
| **Community**            | ~10K+ stars, active OSS ecosystem      | Internal project, no community                                            |

---

## Developer experience comparison

| Dimension           | Orama                                                | @coda/search                                                                    |
| ------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Getting started** | `npm i @orama/orama`, 5 lines to first search        | `pnpm add @coda/search`, implement interfaces, call `init()` (~20 lines)        |
| **API surface**     | Simple: `create()`, `insert()`, `search()`           | Rich: `SearchEngine`, `HybridSearch`, `SearchPipeline` with config objects      |
| **Type safety**     | TypeScript with schema inference                     | Full TypeScript generics: `SearchEngine<TRaw, TDoc, TContext>`                  |
| **Extensibility**   | Plugin system                                        | Interface-based DI: `SearchStage`, `StaticSignal`, `QuerySignal`, `ScoreFusion` |
| **Learning curve**  | Very low — familiar CRUD-like API                    | Moderate — requires understanding interfaces, signals, stages                   |
| **Documentation**   | docs.orama.com — comprehensive with framework guides | 6 doc pages + 8 progressive examples + cookbook + TSDoc on every export         |
| **Bundle size**     | <2KB core — excellent for frontend                   | ~150KB — server-only is fine, not suitable for client-side                      |

---

## Scope & limitations

### What Orama does that we don't need

1. Browser/edge runtime support (we're server-only)
2. 30-language stemming (our corpus is English)
3. Geosearch (irrelevant for schema discovery)
4. Auto-suggestions UI (agent-only consumer)
5. Framework integrations (Docusaurus, Vitepress, Astro)

### What we do that Orama doesn't

1. Schema-aware search with FK inference and graph-augmented results
2. 5 graph-based ranking signals (degree, adamic-adar, betweenness, column-density, proximity)
3. Domain glossary expansion without LLM calls
4. 10-signal RRF fusion (vs simple linear combination)
5. Two-phase initialization with graceful degradation
6. Quantized HNSW (4x memory reduction)
7. Formal evaluation framework with NDCG/MRR regression guards
8. Per-signal score breakdown via `explain()` mode
9. Graph exploration RPCs (join paths, neighbors, detail)
10. Production lifecycle management (state machine, abort coordination, snapshot versioning)

---

## Verdict & recommendations

### If we started fresh, would we use Orama instead?

**No.** Orama is an excellent general-purpose search engine, but it lacks the three capabilities that are fundamental to schema discovery:

1. **Graph signals** — schema search depends on understanding relationships between tables. Orama has no graph concept.
2. **Glossary expansion** — domain-specific synonym mapping is critical for bridging business language to schema identifiers.
3. **Multi-signal RRF fusion** — combining 10 heterogeneous signals requires mathematically principled fusion, not simple linear combination.

### What are we doing better?

- **Retrieval quality**: 10-signal RRF fusion produces NDCG=0.887, MRR=0.943 on schema queries. Orama's hybrid mode would score significantly lower on our benchmark due to missing graph and glossary signals.
- **Domain specialization**: Schema-aware search with FK inference, join path discovery, and graph augmentation.
- **Production robustness**: State machine, two-phase init, graceful degradation, 28 event types, snapshot versioning.

### What is Orama doing better?

- **Developer onboarding**: 5 lines to first search vs ~20 lines. Orama is dramatically easier to get started with.
- **Runtime flexibility**: Browser, edge, Deno support. We're server-only.
- **Bundle size**: <2KB vs ~150KB. Irrelevant for our use case but impressive engineering.
- **Community**: ~10K+ stars, active ecosystem, framework integrations.

### Overall assessment

Orama and @coda/search target different problems. Orama excels at general-purpose search with minimal setup — ideal for documentation sites, e-commerce, and frontend search boxes. @coda/search excels at domain-specific schema discovery with graph-aware ranking — purpose-built for AI agent tool selection over structured metadata. The systems are complementary, not competitive.

---

## References

- [Orama GitHub](https://github.com/oramasearch/orama) — ~10K+ stars, MIT license
- [Orama Documentation](https://docs.orama.com/)
- [OramaCore](https://github.com/oramasearch/oramacore) — server-side runtime
- LightRAG comparison: [lightrag-comparison.md](lightrag-comparison.md)
- ChromaFs comparison: [chromafs-comparison.md](chromafs-comparison.md)
