migration guide
Migrate from Meilisearch to altor-vec
Drop your Meilisearch server and switch to zero-infrastructure semantic browser search with altor-vec. Migration guide for teams moving from full-text to embedding-based retrieval.
When migration makes sense
- Your Meilisearch instance handles public-facing search that could run entirely client-side
- You want semantic search that finds results by meaning, not just keyword matching
- You want to eliminate server deployment, maintenance, and Meilisearch Cloud costs
What you give up
Migration is not always the right call. altor-vec cannot replace Meilisearch for:
- Real-time indexing: Meilisearch updates are instant; altor-vec requires a rebuild step
- Typo tolerance and keyword ranking: Meilisearch's text-search ranking is excellent for exact and near-exact queries
- Advanced filtering: Meilisearch has a powerful filter syntax with attributes, geo-search, and facets
Step-by-step migration
npm install altor-vec @xenova/transformers// 1. Export documents from Meilisearch
import { MeiliSearch } from 'meilisearch';
import { writeFileSync } from 'fs';
const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'your-key' });
const index = client.index('your-index');
// Export all documents (paginated)
const docs = [];
let offset = 0;
while (true) {
const result = await index.getDocuments({ limit: 1000, offset });
docs.push(...result.results);
if (result.results.length < 1000) break;
offset += 1000;
}
writeFileSync('meilisearch-export.json', JSON.stringify(docs));
console.log(`Exported ${docs.length} documents`);
// 2. Embed and build altor-vec index
import { pipeline } from '@xenova/transformers';
import init, { WasmSearchEngine } from 'altor-vec';
await init();
const embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
const DIM = 384;
const vectors = new Float32Array(docs.length * DIM);
for (const [i, doc] of docs.entries()) {
const text = [doc.title, doc.description, doc.content].filter(Boolean).join('. ');
const out = await embedder(text.slice(0, 512), { pooling: 'mean', normalize: true });
vectors.set(out.data, i * DIM);
}
const engine = WasmSearchEngine.from_vectors(vectors, DIM, 16, 200, 50);
writeFileSync('public/search-index.json', engine.to_json());
writeFileSync('public/docs-metadata.json', JSON.stringify(
docs.map(d => ({ id: d.id, title: d.title, url: d.url }))
));
After migration
Once your index is built and deployed to public/search-index.json, load it in the browser:
import init, { WasmSearchEngine } from 'altor-vec';
import { pipeline } from '@xenova/transformers';
await init();
const embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
const resp = await fetch('/search-index.json');
const engine = WasmSearchEngine.from_json(await resp.text());
async function search(query, k = 5) {
const out = await embedder(query, { pooling: 'mean', normalize: true });
const hits = JSON.parse(engine.search(new Float32Array(out.data), k));
return hits; // [{id, score}] - map id back to your metadata
}
Frequently asked questions
What's the main difference between Meilisearch and altor-vec search?
Meilisearch does full-text search: it indexes words, handles typos, and ranks by keyword relevance. altor-vec does semantic search: it finds documents that are conceptually similar to the query using vector embeddings, even when no words match exactly.
Which content types are good candidates for migrating from Meilisearch to altor-vec?
Good candidates: static documentation, blog archives, FAQ pages, knowledge bases that don't update frequently. Bad candidates: e-commerce product catalogs with frequent updates, real-time content feeds, sites where typo tolerance is critical.
How do I handle index updates after migrating?
Run your embed-and-index build script as part of your CI/CD pipeline. For Vercel or Netlify, add it as a build command. The index rebuilds on every deploy — typically fast enough for content that updates weekly or daily.
Can altor-vec handle French, Spanish, or other languages?
Yes, with the right embedding model. Use multilingual-e5-small (384 dimensions) or paraphrase-multilingual-MiniLM-L12-v2 via Transformers.js. These models understand multiple languages and will find semantically similar results across languages.