{"id":51604731,"url":"https://github.com/altor-lab/altor-vec","last_synced_at":"2026-07-31T02:00:56.434Z","repository":{"id":343474599,"uuid":"1177899651","full_name":"Altor-lab/altor-vec","owner":"Altor-lab","description":"Client-side vector search powered by HNSW. 54KB gzipped WASM. Sub-millisecond latency.","archived":false,"fork":false,"pushed_at":"2026-07-03T04:43:55.000Z","size":762,"stargazers_count":50,"open_issues_count":2,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T06:25:10.387Z","etag":null,"topics":["embeddings","hnsw","nearest-neighbor","rust","semantic-search","vector-search","wasm","webassembly"],"latest_commit_sha":null,"homepage":"https://altorlab.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Altor-lab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-10T13:41:12.000Z","updated_at":"2026-07-03T05:53:53.000Z","dependencies_parsed_at":"2026-03-10T20:00:24.635Z","dependency_job_id":null,"html_url":"https://github.com/Altor-lab/altor-vec","commit_stats":null,"previous_names":["altor-lab/altor-vec"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Altor-lab/altor-vec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altor-lab%2Faltor-vec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altor-lab%2Faltor-vec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altor-lab%2Faltor-vec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altor-lab%2Faltor-vec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Altor-lab","download_url":"https://codeload.github.com/Altor-lab/altor-vec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altor-lab%2Faltor-vec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36098609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-31T02:00:06.731Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embeddings","hnsw","nearest-neighbor","rust","semantic-search","vector-search","wasm","webassembly"],"created_at":"2026-07-12T01:00:27.742Z","updated_at":"2026-07-31T02:00:56.423Z","avatar_url":"https://github.com/Altor-lab.png","language":"TypeScript","funding_links":[],"categories":["Awesome Vector Search Engine"],"sub_categories":["Library"],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003ealtor-vec\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\u003cb\u003eClient-side vector search. Rust + WASM. 54KB. Sub-millisecond.\u003c/b\u003e\u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.npmjs.com/package/altor-vec\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/altor-vec?color=blue\u0026label=npm\" alt=\"npm version\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/altor-vec\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/altor-vec?color=green\" alt=\"npm downloads\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/altor-lab/altor-vec/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/altor-lab/altor-vec/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/altor-lab/altor-vec/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/altor-lab/altor-vec?style=social\" alt=\"GitHub stars\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/altor-lab/altor-vec/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/WASM-54KB_gzipped-orange\" alt=\"WASM size\"\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://altorlab.dev\"\u003e\u003cimg src=\"https://img.shields.io/badge/%F0%9F%9A%80_Docs_%26_Demo-altorlab.dev-blueviolet?style=for-the-badge\" alt=\"Docs \u0026 Demo\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n---\n\n**Zero server. Zero API keys. Zero per-query cost. Your users' data never leaves their browser.**\n\naltor-vec is an HNSW vector similarity search engine written in Rust that compiles to 54KB of WebAssembly. Search 10,000 vectors in under 1ms — entirely client-side.\n\n## Is this for you?\n\n- **Docs site** — want semantic search without Algolia DocSearch fees?\n- **Using Fuse.js** — need it to understand *meaning*, not just character similarity? (\"cancel subscription\" should find \"end your plan\")\n- **React / Next.js app** — want vector search without a server or API keys?\n- **Privacy requirement** — queries must never leave the device?\n\n## Why altor-vec?\n\n| | altor-vec | Algolia | Fuse.js | Orama | Voy |\n|---|---|---|---|---|---|\n| **Runs client-side** | ✅ | ❌ server | ✅ | ✅ | ✅ |\n| **Semantic (meaning-based)** | ✅ HNSW | ✅ paid add-on | ❌ fuzzy text | partial | ❌ |\n| **Bundle size** | **54KB** gz | N/A | ~5KB | ~2KB* | 75KB gz |\n| **p95 latency** | **0.6ms** | ~50ms (network) | ~2ms | ~5ms | ~2ms |\n| **Per-query cost** | **$0** | $0.50/1K | $0 | $0 | $0 |\n| **\"cancel\" → \"end subscription\"** | ✅ | ✅ | ❌ | partial | ❌ |\n\n\u003csub\u003e*Orama's 2KB is keyword-only; vector search adds significant size.\u003c/sub\u003e\n\n### vs Fuse.js\n\nFuse.js is great for fuzzy *string* matching. altor-vec does *semantic* matching — meaning, not characters.\n\n| | altor-vec | Fuse.js |\n|---|---|---|\n| Algorithm | HNSW (vector similarity) | Bitap / Levenshtein |\n| \"cancel plan\" → \"end subscription\" | ✅ | ❌ |\n| Typo tolerance | Via semantic neighbors | ✅ native |\n| Bundle size | 54KB WASM | ~5KB |\n| Needs embeddings | Yes (build-time) | No |\n\n→ Full comparison: [altorlab.dev/vs/fuse-js](https://altorlab.dev/vs/fuse-js)\n\n## Get started in 30 seconds\n\n```bash\nnpm install altor-vec\n```\n\n```js\nimport init, { WasmSearchEngine } from 'altor-vec';\n\nawait init();\n\nconst resp = await fetch('/search-index.bin');\nconst engine = WasmSearchEngine.from_bytes(new Uint8Array(await resp.arrayBuffer()));\n\n// Search returns in \u003c1ms\nconst results = JSON.parse(engine.search(queryEmbedding, 5));\n// =\u003e [[nodeId, distance], ...]\n```\n\n→ Full guide: [altorlab.dev/getting-started](https://altorlab.dev/getting-started)\n\n## Framework quickstarts\n\n### React\n\n```jsx\nimport { useState, useEffect, useRef } from 'react';\nimport init, { WasmSearchEngine } from 'altor-vec';\n\nexport function SearchWidget({ docs }) {\n  const engineRef = useRef(null);\n  const [results, setResults] = useState([]);\n\n  useEffect(() =\u003e {\n    init().then(async () =\u003e {\n      const res = await fetch('/search-index.bin');\n      engineRef.current = WasmSearchEngine.from_bytes(\n        new Uint8Array(await res.arrayBuffer())\n      );\n    });\n  }, []);\n\n  async function handleSearch(queryEmbedding) {\n    const hits = JSON.parse(engineRef.current.search(queryEmbedding, 5));\n    setResults(hits.map(([id]) =\u003e docs[id]));\n  }\n\n  return \u003cinput onChange={e =\u003e /* embed then handleSearch() */ null} /\u003e;\n}\n```\n\n→ [altorlab.dev/guides/react/document-search](https://altorlab.dev/guides/react/document-search)\n\n### Next.js (App Router)\n\n```jsx\n'use client';\nimport { useRef, useEffect } from 'react';\nimport init, { WasmSearchEngine } from 'altor-vec';\n\nexport default function Search() {\n  const engineRef = useRef(null);\n  useEffect(() =\u003e {\n    init().then(async () =\u003e {\n      const res = await fetch('/search-index.bin');\n      engineRef.current = WasmSearchEngine.from_bytes(\n        new Uint8Array(await res.arrayBuffer())\n      );\n    });\n  }, []);\n  // ...\n}\n```\n\n→ [altorlab.dev/guides/nextjs/document-search](https://altorlab.dev/guides/nextjs/document-search)\n\n### Vue 3\n\n```vue\n\u003cscript setup\u003e\nimport { onMounted } from 'vue';\nimport init, { WasmSearchEngine } from 'altor-vec';\nlet engine;\nonMounted(async () =\u003e {\n  await init();\n  const res = await fetch('/search-index.bin');\n  engine = WasmSearchEngine.from_bytes(new Uint8Array(await res.arrayBuffer()));\n});\n\u003c/script\u003e\n```\n\n→ [altorlab.dev/guides/vue/document-search](https://altorlab.dev/guides/vue/document-search)\n\n## Building the index (once, at deploy time)\n\n```js\n// scripts/build-search-index.mjs\nimport { pipeline } from '@huggingface/transformers';\nimport { WasmSearchEngine } from 'altor-vec/node';\nimport fs from 'fs';\n\nconst embed = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');\nconst docs = [\n  { id: 0, text: 'How to cancel your subscription' },\n  { id: 1, text: 'Account settings and profile preferences' },\n  { id: 2, text: 'Getting started with the API' },\n];\n\nconst vectors = [];\nfor (const doc of docs) {\n  const out = await embed(doc.text, { pooling: 'mean', normalize: true });\n  vectors.push(...Array.from(out.data));\n}\n\nconst engine = WasmSearchEngine.from_vectors(\n  new Float32Array(vectors), 384, 16, 200, 50\n);\nfs.writeFileSync('./public/search-index.bin', Buffer.from(engine.serialize()));\n```\n\nAdd to `package.json`:\n```json\n{ \"scripts\": { \"prebuild\": \"node scripts/build-search-index.mjs\", \"build\": \"vite build\" } }\n```\n\n## Web Worker (recommended for production)\n\n```js\n// search-worker.js\nimport init, { WasmSearchEngine } from 'altor-vec';\nlet engine;\nself.onmessage = async (e) =\u003e {\n  if (e.data.type === 'init') {\n    await init();\n    const resp = await fetch(e.data.indexUrl);\n    engine = WasmSearchEngine.from_bytes(new Uint8Array(await resp.arrayBuffer()));\n    postMessage({ type: 'ready' });\n  }\n  if (e.data.type === 'search') {\n    const results = JSON.parse(engine.search(new Float32Array(e.data.query), e.data.topK));\n    postMessage({ type: 'results', results });\n  }\n};\n```\n\n## Benchmarks\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e\n\n**Latency** (10K vectors, 384d)\n\n| Environment | p95 |\n|---|---|\n| Chrome | **0.60ms** |\n| Node.js | **0.50ms** |\n| Native Rust | **0.26ms** |\n\n\u003c/td\u003e\u003ctd\u003e\n\n**Size**\n\n| Asset | Size |\n|---|---|\n| `.wasm` gzipped | **54KB** |\n| `.wasm` raw | 117KB |\n| Index (10K/384d) | 17MB |\n\n\u003c/td\u003e\u003c/tr\u003e\n\u003c/table\u003e\n\n→ [altorlab.dev/benchmarks](https://altorlab.dev/benchmarks/)\n\n## API\n\n| Method | Description |\n|---|---|\n| `WasmSearchEngine.from_bytes(bytes)` | Load serialized index |\n| `WasmSearchEngine.from_vectors(flat, dims, m, ef_c, ef_s)` | Build from flat float array |\n| `.search(query, topK)` | Returns JSON `[[id, dist], ...]` |\n| `.add_vectors(flat, dims)` | Add vectors to existing index |\n| `.serialize()` | Serialize to `Uint8Array` |\n| `.len()` | Vector count |\n| `.free()` | Free WASM memory |\n\n**HNSW params:** `m=16` (connections/node), `ef_construction=200` (build quality), `ef_search=50` (query recall)\n\n→ Full reference: [altorlab.dev/api](https://altorlab.dev/api)\n\n## Embedding models\n\n| Model | Dims | Runs in browser |\n|---|---|---|\n| all-MiniLM-L6-v2 | 384 | ✅ via [Transformers.js](https://huggingface.co/docs/transformers.js) |\n| nomic-embed-text | 768 | ✅ via Transformers.js |\n| text-embedding-3-small | 1536 | Build-time only (OpenAI API) |\n| embed-english-v3 | 1024 | Build-time only (Cohere API) |\n\n## Common use cases\n\n- **Documentation search** — [altorlab.dev/use-cases/document-search](https://altorlab.dev/use-cases/document-search)\n- **Browser RAG** (retrieval without a server) — [altorlab.dev/blog/browser-rag-tutorial](https://altorlab.dev/blog/browser-rag-tutorial)\n- **Product search** — [altorlab.dev/use-cases/product-search](https://altorlab.dev/use-cases/product-search)\n- **Semantic autocomplete** — [altorlab.dev/use-cases/autocomplete](https://altorlab.dev/use-cases/autocomplete)\n- **Offline-first search** — [altorlab.dev/use-cases/offline-search](https://altorlab.dev/use-cases/offline-search)\n- **Chat memory** — [altorlab.dev/use-cases/chat-memory](https://altorlab.dev/use-cases/chat-memory)\n\n## Migration guides\n\n- Algolia → [altorlab.dev/migrate-from/algolia](https://altorlab.dev/migrate-from/algolia)\n- Pinecone → [altorlab.dev/migrate-from/pinecone](https://altorlab.dev/migrate-from/pinecone)\n- Fuse.js → [altorlab.dev/vs/fuse-js](https://altorlab.dev/vs/fuse-js)\n- Pagefind → [altorlab.dev/migrate-from/pagefind](https://altorlab.dev/migrate-from/pagefind)\n- ChromaDB → [altorlab.dev/migrate-from/chromadb](https://altorlab.dev/migrate-from/chromadb)\n- FAISS → [altorlab.dev/migrate-from/faiss](https://altorlab.dev/migrate-from/faiss)\n- Meilisearch → [altorlab.dev/migrate-from/meilisearch](https://altorlab.dev/migrate-from/meilisearch)\n- Typesense → [altorlab.dev/migrate-from/typesense](https://altorlab.dev/migrate-from/typesense)\n\n## How it works\n\naltor-vec uses **HNSW (Hierarchical Navigable Small World)** — the same algorithm behind Pinecone, Qdrant, and pgvector. Builds a multi-layer graph; upper layers are express lanes for coarse navigation, bottom layer has all vectors for fine-grained search. O(log n) queries. All vectors are L2-normalized at insert so dot product = cosine similarity.\n\n## Architecture\n\n```\nsrc/\n├── lib.rs              # Public API\n├── distance.rs         # Dot product + normalization (SIMD-vectorized)\n└── hnsw/\n    ├── mod.rs          # HnswIndex: API + serialization\n    ├── graph.rs        # Layered graph structure\n    ├── search.rs       # Greedy beam search\n    └── construction.rs # Insert + random layer selection\nwasm/\n└── src/lib.rs          # WasmSearchEngine (wasm-bindgen wrapper)\n```\n\n## Full documentation\n\n| | |\n|---|---|\n| Getting started | [altorlab.dev/getting-started](https://altorlab.dev/getting-started) |\n| API reference | [altorlab.dev/api](https://altorlab.dev/api) |\n| React guide | [altorlab.dev/guides/react/document-search](https://altorlab.dev/guides/react/document-search) |\n| Next.js guide | [altorlab.dev/guides/nextjs/document-search](https://altorlab.dev/guides/nextjs/document-search) |\n| Vue guide | [altorlab.dev/guides/vue/document-search](https://altorlab.dev/guides/vue/document-search) |\n| Node.js guide | [altorlab.dev/guides/node/document-search](https://altorlab.dev/guides/node/document-search) |\n| All comparisons | [altorlab.dev/vs](https://altorlab.dev/vs/) |\n| Migration guides | [altorlab.dev/migrate-from](https://altorlab.dev/migrate-from/) |\n| Benchmarks | [altorlab.dev/benchmarks](https://altorlab.dev/benchmarks/) |\n| Live examples | [altorlab.dev/examples/document-search](https://altorlab.dev/examples/document-search) |\n\n## Build from source\n\n```bash\ncargo test\ncargo bench\ncd wasm \u0026\u0026 wasm-pack build --target web --release\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for build instructions, code style, and PR process.\n\n## License\n\n[MIT](LICENSE)\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eBuilt by \u003ca href=\"https://github.com/altor-lab\"\u003ealtor-lab\u003c/a\u003e\u003c/b\u003e ·\n  \u003ca href=\"https://altorlab.dev\"\u003ealtorlab.dev\u003c/a\u003e ·\n  \u003ca href=\"https://www.npmjs.com/package/altor-vec\"\u003enpm\u003c/a\u003e ·\n  \u003ca href=\"https://github.com/altor-lab/altor-vec/issues\"\u003eissues\u003c/a\u003e ·\n  \u003ca href=\"mailto:anshul@altorlab.com\"\u003eanshul@altorlab.com\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltor-lab%2Faltor-vec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faltor-lab%2Faltor-vec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltor-lab%2Faltor-vec/lists"}