TLDR: For text RAG, default to OpenAI
text-embedding-3-small. Competitive quality, you probably already have the key, one fewer billing surface. Voyage earns its place for multimodal/image search — but that's a different problem entirely.
The Setup
I was building RAG for an internal canvas tool — it maps out SOPs as a React Flow graph, with a bottom-drawer chat so you can actually ask the documentation questions.
Good problem. Needed embeddings. Apollo, my AI coding agent, reached for Voyage-3 without much ceremony.
(It was sitting in the plan template. That's the whole reason. Not a great reason.)
The Push-back I Needed
I asked the obvious question: "Why are we using Voyage for RAG?"
The honest answer: no strong reason.
OpenAI's text-embedding-3-small is GENUINELY competitive for most text retrieval tasks, I already had the API key in the project, and adding Voyage meant a second billing surface I'd have to think about forever.
Oh — and Voyage's SDK ESM bundle had a fight with Turbopack. Nothing fatal, just the kind of packaging headache that makes you resent a dependency from day one.
We swapped it out. One commit…
Done.
Why OpenAI Wins for Text RAG
Three reasons, in order of how much I actually care:
- One provider to manage. I've already got
OPENAI_API_KEYin my stack. One key, one billing page, one thing to rotate when it leaks. text-embedding-3-smallis genuinely good. 1536 dimensions, solid retrieval quality, and cheap enough that cost barely registers.- Plain fetch is all you need.
POST https://api.openai.com/v1/embeddings— no SDK, smaller bundle, nothing to break.
The Exceptions (Because There Are Always Exceptions)
This is NOT a blanket "use OpenAI for everything" rule.
OpenAI's embeddings API is text-only. Full stop. No image pixels. So when I was building image search for a DAM (digital asset management system), OpenAI was simply off the table. That project went to Voyage voyage-multimodal-3 — managed, no model to host, handles text and image vectors in the same space. Exactly the right tool for the problem.
And my own memory/vault RAG — the thing Apollo uses to recall notes and past decisions — runs on text-embedding-3-large (3072 dimensions, not 1536). The corpus is dense and semantically nuanced. The cost delta between large and small on my corpus is negligible. Not worth optimizing. Retrieval quality is worth optimizing.
One more thing: Anthropic has no embeddings endpoint. Claude is generative-only. Their own recommendation is Voyage. So if you're building with Claude, you're already reaching for a second provider — which is one more reason to consolidate on OpenAI for text and keep Voyage as the specialist for multimodal.
Why This Actually Matters
Every extra provider you add is a key to rotate, a billing page to check, an SDK to update, and a bundle to babysit.
Start with what you already have. OpenAI for text. Voyage when you genuinely need multimodal. Upgrade from 3-small to 3-large only when your corpus earns it.
Don't pick your embedding provider from a template. Pick it from your stack.
P.S. If you're switching embedding models mid-project — dimension mismatch will bite you. The
vec0virtual table hard-binds dimensions atCREATE TABLEtime. Changing models means dropping the DB and re-ingesting everything. Guard at the embed boundary: throw ife.length !== EMBED_DIM. Future you will thank present you.