Summary
Every retrieval-augmented generation (RAG) feature needs somewhere to store embeddings and search them quickly. In 2026 the three options that come up most often in architecture reviews are pgvector (vector search inside PostgreSQL), Qdrant (an open-source, purpose-built vector database written in Rust) and Pinecone (a fully managed, serverless vector database). All three are production-ready. The right choice depends far more on your data size, filtering needs, team skills and budget than on headline benchmark numbers.
Our short answer: if you already run PostgreSQL and your corpus is in the low millions of chunks, start with pgvector. Move to Qdrant when you need consistently low latency at larger scale, heavy metadata filtering or native hybrid search, and you are comfortable running (or paying for) another service. Choose Pinecone when "zero infrastructure" is a hard requirement and you are happy to trade cost control for convenience. The rest of this guide explains the trade-offs, shows code for each option and gives you a decision checklist you can use with your team.
What a vector database actually does in a RAG system
In a RAG pipeline you split documents into chunks, turn each chunk into an embedding (a list of numbers that captures its meaning) and store those embeddings. At query time you embed the user's question, find the nearest chunks, and pass them to the LLM as context. If you are new to the pattern, our guide on RAG and LangChain in production walks through a full pipeline.
The vector store is responsible for four things:
- Approximate nearest neighbour (ANN) search - usually with an HNSW graph index, which trades a tiny amount of recall for very fast lookups.
- Filtering - restricting results by tenant, user permissions, document type, language or date. In multi-tenant SaaS this is not optional; it is a security boundary.
- Hybrid retrieval - combining semantic (dense) search with keyword (sparse/BM25-style) search, which noticeably helps with product codes, names and exact phrases.
- Operations - backups, scaling, re-indexing when you change embedding models, and monitoring.
Keep these four in mind. Most "which vector database" debates are really debates about filtering and operations, not raw speed.
pgvector: vector search inside the PostgreSQL you already run
pgvector is an open-source PostgreSQL extension that adds a vector column type, distance operators and two index types (HNSW and IVFFlat). It is available on the major managed Postgres services, including Amazon RDS and Aurora, Google Cloud SQL and AlloyDB, Azure Database for PostgreSQL, Supabase and Neon.
Why teams choose it
- One database. Embeddings live next to the rows they describe. You get transactions, joins, foreign keys, row-level security and your existing backup and point-in-time recovery.
- No sync problems. When a document is deleted or a customer's access changes, the embedding changes in the same transaction. With a separate vector store you must build and monitor that sync yourself.
- Familiar tooling. Laravel, Django, Prisma and most ORMs can work with it, and your team already knows SQL.
- Lowest incremental cost at small to medium scale, because you are often using spare capacity on an instance you already pay for.
Where it gets harder
- Memory. HNSW indexes perform best when they fit in RAM. As vectors grow into the tens of millions, you need bigger instances, and vector search starts competing with your transactional workload. Many teams solve this with a read replica dedicated to retrieval.
- Filtered search. Combining a vector index with a selective
WHEREclause can return fewer results than requested, because the index finds the nearest neighbours first and the filter removes many of them. Recent pgvector releases (0.8 and later) added iterative index scans to address this, and partial indexes or partitioning by tenant also help, but it needs testing. - Index builds on large tables are memory- and CPU-intensive, so plan them for quiet periods and tune
maintenance_work_mem.
pgvector in practice
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE document_chunks (
id bigserial PRIMARY KEY,
tenant_id bigint NOT NULL,
document_id bigint NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
content text NOT NULL,
embedding vector(1536) NOT NULL
);
-- HNSW index using cosine distance
CREATE INDEX ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
CREATE INDEX ON document_chunks (tenant_id);
-- Query: top 8 chunks for one tenant
SET hnsw.ef_search = 100;
SET hnsw.iterative_scan = relaxed_order; -- pgvector 0.8+
SELECT id, content, 1 - (embedding <=> $1) AS similarity
FROM document_chunks
WHERE tenant_id = $2
ORDER BY embedding <=> $1
LIMIT 8;
In a Laravel application this is a raw expression away. Packages such as pgvector/pgvector-php add a cast and query helpers, but plain bindings work fine:
$vector = '[' . implode(',', $embedding) . ']';
$chunks = DB::table('document_chunks')
->select('id', 'content')
->selectRaw('1 - (embedding <=> ?::vector) AS similarity', [$vector])
->where('tenant_id', $tenantId)
->orderByRaw('embedding <=> ?::vector', [$vector])
->limit(8)
->get();
If you are still choosing a primary database for your product, see our comparison of PostgreSQL vs MySQL for SaaS; native vector support through pgvector is one of the reasons many AI products now default to Postgres.
Qdrant: a purpose-built, open-source vector engine
Qdrant is a vector database written in Rust and released under the Apache 2.0 licence. You can self-host it with Docker or Kubernetes, or use Qdrant Cloud (including hybrid and private-cloud deployments). Each point stores a vector plus a JSON "payload" that you can filter on.
Why teams choose it
- Filtering is built into the search. Qdrant applies payload filters during graph traversal rather than after it, and you can create payload indexes on fields you filter by often. For multi-tenant SaaS with strict per-tenant filters, this tends to be more predictable than bolting a filter onto an ANN index.
- Native hybrid search. A collection can hold dense and sparse vectors side by side, and the Query API can fuse results (for example with reciprocal rank fusion) in a single request.
- Quantization. Scalar, product and binary quantization shrink the memory footprint of large collections, which is often the biggest cost lever at scale.
- Multi-vector and named vectors let you store several embeddings per item, useful when you test a new embedding model alongside the old one or use late-interaction models.
Where it gets harder
- A second system to operate. You now have to keep Qdrant in sync with your primary database, handle deletes and permission changes, and back it up separately (Qdrant supports snapshots).
- Self-hosting needs real ops skills for clustering, sharding and upgrades. Qdrant Cloud removes most of that, at a price.
Qdrant in practice (Python)
from qdrant_client import QdrantClient, models
client = QdrantClient(url="https://your-qdrant-host:6333", api_key=QDRANT_API_KEY)
client.create_collection(
collection_name="document_chunks",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
)
client.create_payload_index(
collection_name="document_chunks",
field_name="tenant_id",
field_schema=models.PayloadSchemaType.INTEGER,
)
hits = client.query_points(
collection_name="document_chunks",
query=query_embedding,
query_filter=models.Filter(
must=[models.FieldCondition(key="tenant_id", match=models.MatchValue(value=tenant_id))]
),
limit=8,
).points
Pinecone: fully managed and serverless
Pinecone is a proprietary, fully managed vector database. Its serverless indexes separate storage from compute, so you do not size servers; you pay based on storage and the reads and writes you perform. It offers namespaces (a natural fit for per-tenant isolation), metadata filtering, sparse-dense hybrid search and SDKs for Python, Node.js, Java and Go, plus integrated embedding and reranking options.
Why teams choose it
- Zero infrastructure. No index tuning, no capacity planning, no upgrades. A small team can have production retrieval running in an afternoon.
- Scales without re-architecture as your corpus grows from thousands to hundreds of millions of vectors.
- Namespaces keep tenants physically separated and make deleting a customer's data straightforward.
Where it gets harder
- Cost predictability. Usage-based pricing is cheap at low volume and can become significant with high query traffic or large corpora. Model your expected reads and writes against the current price list before committing.
- Vendor lock-in and data residency. It is a closed, hosted service. Check available cloud regions against your GDPR or customer contract requirements.
- Same sync problem as Qdrant - your source of truth still lives elsewhere.
Pinecone in practice (Node.js)
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.index('document-chunks').namespace(`tenant-${tenantId}`);
const result = await index.query({
vector: queryEmbedding,
topK: 8,
includeMetadata: true,
filter: { docType: { $eq: 'policy' } },
});
const context = result.matches.map((m) => m.metadata.content);
pgvector vs Qdrant vs Pinecone: side-by-side
| Factor | pgvector | Qdrant | Pinecone |
|---|---|---|---|
| Licence / model | Open source Postgres extension | Open source (Apache 2.0) + managed cloud | Proprietary, fully managed |
| Best fit scale | Small to mid (low tens of millions with tuning) | Mid to very large | Any, with no ops |
| Filtering | Full SQL; needs care with selective filters | Strong, payload indexes, filter-aware search | Metadata filters + namespaces |
| Hybrid search | Combine with Postgres full-text search yourself | Native dense + sparse with fusion | Sparse-dense supported |
| Data consistency | Transactional with your app data | Separate sync pipeline | Separate sync pipeline |
| Ops effort | Low if you already run Postgres | Medium self-hosted, low on Cloud | Very low |
| Cost profile | Mostly existing database compute | Server/RAM based; quantization helps | Usage based (storage, reads, writes) |
| Self-hosting / residency | Anywhere Postgres runs | Anywhere, including on-prem | Pinecone-hosted regions |
Public benchmarks exist for all three, but treat them carefully. Results depend heavily on dimensions, hardware, index parameters, recall targets and filter selectivity. For RAG, recall at your filter pattern matters more than raw queries per second, and the LLM call almost always dominates end-to-end latency. Benchmark on your own data before you decide.
A practical decision guide
Choose pgvector if
- Your product already runs on PostgreSQL.
- Your corpus is up to a few million chunks today, with moderate growth.
- You need strict consistency between documents, permissions and embeddings (for example, a deleted file must never appear in answers).
- You want the fewest moving parts and the lowest monthly bill.
Choose Qdrant if
- You expect tens of millions of vectors or more, or need consistently low retrieval latency under load.
- Your queries combine vectors with complex or highly selective filters.
- Hybrid (keyword + semantic) retrieval is central to answer quality.
- You need self-hosting for data residency, on-prem customers or cost control at scale.
Choose Pinecone if
- You have no appetite for running database infrastructure.
- You need to launch quickly and scale unpredictably.
- Usage-based pricing fits your budget at your projected traffic.
Design so you can switch later
Whichever store you pick, a few design choices keep you from being locked in:
- Wrap retrieval behind an interface (for example a
VectorStorecontract in Laravel or a repository module in Node.js) withupsert,deleteandsearchmethods. LangChain and LlamaIndex already provide this abstraction if you use them. - Keep the source of truth in your main database. Store chunk text, metadata and the embedding model version there, so you can rebuild any vector index from scratch.
- Version your embeddings. When you change embedding models you must re-embed everything; write into a new index or column and switch reads only once it is complete.
- Use an outbox or queue for indexing, so document changes reliably reach an external vector store and failed writes are retried.
- Build a small evaluation set of real questions with known correct chunks. Measure recall and answer quality before and after any change of store, index settings or chunking.
Security and multi-tenancy checklist
- Never rely on the LLM prompt to enforce access control; filter by tenant and permission at retrieval time.
- In pgvector, consider Postgres row-level security on chunk tables. In Qdrant, use mandatory payload filters or separate collections or shards for large tenants. In Pinecone, use one namespace per tenant.
- Keep vector store API keys server-side only, scoped per environment, and rotate them.
- Remember that embeddings are derived from customer data. Include them in your data-deletion and retention processes.
FAQ
Is pgvector good enough for production RAG?
Yes. Many production AI products run retrieval on pgvector with HNSW indexes. It works best when your corpus fits comfortably in memory on your Postgres instance and you test filtered queries carefully.
When should we move from pgvector to a dedicated vector database?
Consider it when retrieval latency rises under real load, index memory starts to crowd out your transactional workload, filtered queries return incomplete results despite tuning, or you need native hybrid search at scale.
Is Qdrant cheaper than Pinecone?
It often is at larger scale, especially self-hosted with quantization, because you pay for servers rather than per operation. But self-hosting adds engineering time. Compare total cost, including people, using your own traffic projections and current price lists.
Do we need hybrid search for RAG?
Not always, but it usually helps when users search for exact terms such as product codes, names, error messages or legal clauses that pure semantic search can miss. Test it on your evaluation set.
Can we use these vector databases with Laravel and Node.js?
Yes. pgvector works through standard Postgres drivers and ORMs, Qdrant has a REST and gRPC API with official clients (including JavaScript and Python), and Pinecone has official Node.js and Python SDKs. Laravel apps can call Qdrant or Pinecone via their HTTP APIs.
How hard is it to switch vector databases later?
Not hard if you keep chunks and metadata in your main database and hide retrieval behind an interface. Switching then means re-indexing and re-running your evaluation, not rewriting your product.
- #AI Integration
- #Laravel
- #Node.js
- #pgvector
- #Pinecone
- #PostgreSQL
- #Python
- #Qdrant
- #RAG
- #Vector Database
Written by
Prakash Tank
Founder & Full-Stack Architect, DayDecoder
Prakash started as a certified Laravel developer and grew into a full-stack architect who owns a project end to end: requirements, architecture, development, deployment, and support. He designs event-driven systems with...
More about Prakash