Every AI feature that works with your own data (semantic search, RAG pipelines, recommendation engines, document classifiers) needs somewhere to store and query vector embeddings. The vector database market has grown from a handful of options to dozens, each with different tradeoffs around performance, operational complexity, cost, and scale.
This guide compares seven vector databases that cover the spectrum: from extending PostgreSQL with an extension to fully managed cloud services to embedded databases that run in-process. The right choice depends on your existing infrastructure, the scale of your workload, and how much operational overhead you're willing to take on.
| Database | Type | Hosting | Open Source | Best Scale | Standout Feature |
|---|---|---|---|---|---|
| pgvector | Postgres extension | Self-hosted / managed Postgres | Yes | Millions | Same DB as your app data |
| Pinecone | Managed SaaS | Pinecone cloud | No | Billions | Zero-ops serverless |
| Qdrant | Dedicated vector DB | Self-hosted / Qdrant Cloud | Yes (Apache 2.0) | Hundreds of millions | Payload filtering + Rust perf |
| Weaviate | Dedicated vector DB | Self-hosted / Weaviate Cloud | Yes (BSD-3) | Hundreds of millions | Built-in vectorization modules |
| Milvus | Dedicated vector DB | Self-hosted / Zilliz Cloud | Yes (Apache 2.0) | Billions | GPU-accelerated, enterprise scale |
| Chroma | Embedded / client-server | In-process or self-hosted | Yes (Apache 2.0) | Hundreds of thousands | Developer experience, prototyping |
| LanceDB | Embedded | In-process (serverless cloud in beta) | Yes (Apache 2.0) | Millions | Zero-copy, columnar storage |
pgvector is a PostgreSQL extension that adds a vector column type with support for cosine similarity, L2 distance, and inner product operations. It supports both HNSW and IVFFlat indexing.
Key features:
Best for:
Limitations:
Example:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding vector(1536)
);
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
-- Similarity search with SQL filtering
SELECT id, content, 1 - (embedding <=> $1) AS similarity
FROM documents
WHERE category = 'engineering'
ORDER BY embedding <=> $1
LIMIT 10;
pgvector is the default recommendation for teams that already have Postgres in their stack. It avoids the operational complexity of a second data store and gives you transactional consistency that dedicated vector databases can't match. If you want to try it out, see the getting started section below for a working setup in a few lines of code. For a detailed head-to-head comparison, see pgvector vs Pinecone.
Pinecone is a fully managed vector database offered as a cloud service. You get an API key, create an index, and start querying. No instances to size, no indexes to tune, no infrastructure to manage.
Key features:
Best for:
Limitations:
Example:
import { Pinecone } from "@pinecone-database/pinecone";
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
const index = pc.index("documents");
// Upsert
await index.upsert([{
id: "doc-1",
values: embedding,
metadata: { category: "engineering" },
}]);
// Query
const results = await index.query({
vector: queryEmbedding,
topK: 10,
filter: { category: { $eq: "engineering" } },
includeMetadata: true,
});
Pinecone is the right choice when you need scale and managed infrastructure above everything else. For a detailed comparison with pgvector, see pgvector vs Pinecone.
Qdrant is an open-source vector database written in Rust. It's designed from the ground up for vector search, with a focus on performance, payload filtering, and a rich query API.
Key features:
Best for:
Limitations:
Example:
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({ url: "http://localhost:6333" });
// Create collection
await client.createCollection("documents", {
vectors: { size: 1536, distance: "Cosine" },
});
// Upsert
await client.upsert("documents", {
points: [{
id: 1,
vector: embedding,
payload: { category: "engineering", date: "2026-03-01" },
}],
});
// Search with filtering
const results = await client.search("documents", {
vector: queryEmbedding,
limit: 10,
filter: {
must: [{ key: "category", match: { value: "engineering" } }],
},
});
Qdrant is a strong choice if you need a dedicated vector database and want to stay open-source. If you're using Encore, we have a tutorial for building semantic search with Qdrant. For a comparison with pgvector, see pgvector vs Qdrant.
Weaviate is an open-source vector database that goes beyond storage and search. It includes built-in modules for generating embeddings, so you can insert raw text and Weaviate handles the vectorization.
Key features:
Best for:
Limitations:
Example:
import weaviate from "weaviate-client";
const client = await weaviate.connectToLocal();
// Insert raw text, Weaviate vectorizes it
await client.collections.get("Document").data.insert({
title: "Vector Search Guide",
content: "pgvector adds vector search to PostgreSQL...",
});
// Semantic search
const results = await client.collections.get("Document")
.query.nearText("how does vector search work", { limit: 10 });
Weaviate is interesting if you want embedding generation baked into the database. But the vectorization modules are calling the same APIs you'd call in your application code, so the convenience comes with the tradeoff of less control over the embedding pipeline.
Milvus is an open-source vector database designed for large-scale deployments. Its managed version, Zilliz Cloud, offers enterprise features and GPU-accelerated search.
Key features:
Best for:
Limitations:
Example:
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "localhost:19530" });
await client.createCollection({
collection_name: "documents",
fields: [
{ name: "id", data_type: 5, is_primary_key: true, auto_id: true },
{ name: "embedding", data_type: 101, type_params: { dim: 1536 } },
{ name: "category", data_type: 21, max_length: 256 },
],
});
const results = await client.search({
collection_name: "documents",
vector: queryEmbedding,
limit: 10,
});
Milvus is the heavy-duty option. If you're processing billions of vectors and need GPU acceleration or advanced indexing, it's built for that. For most teams, it's more infrastructure than the workload requires.
Chroma is an open-source embedding database focused on developer experience. It runs in-process (embedded) or as a client-server setup, making it the fastest path from zero to a working vector search.
Key features:
add, query, update, deleteBest for:
Limitations:
Example:
import { ChromaClient } from "chromadb";
const client = new ChromaClient();
const collection = await client.createCollection({ name: "documents" });
// Add with auto-generated embeddings
await collection.add({
ids: ["doc-1"],
documents: ["pgvector adds vector search to PostgreSQL..."],
metadatas: [{ category: "database" }],
});
// Query
const results = await collection.query({
queryTexts: ["how does vector search work"],
nResults: 10,
});
Chroma is great for getting started and testing ideas. For production workloads, you'll likely graduate to pgvector (if you want simplicity) or a dedicated vector database (if you need scale).
LanceDB is an open-source embedded vector database built on the Lance columnar format. It runs in-process with zero-copy access to data, making it fast for local workloads without a running server.
Key features:
Best for:
Limitations:
Example:
import * as lancedb from "lancedb";
const db = await lancedb.connect("data/lancedb");
const table = await db.createTable("documents", [
{ id: 1, text: "pgvector adds vector search...", vector: embedding },
]);
const results = await table.search(queryEmbedding).limit(10).toArray();
LanceDB is worth watching if you're building local-first applications or working in data science workflows where running a server is overhead. For backend services, pgvector or a managed option is usually a better fit.
You already run PostgreSQL (most backend teams do). pgvector adds vector search without adding infrastructure. Documents and embeddings live in the same table, in the same transaction. You use SQL for filtering. There's no sync pipeline, no extra credentials, no new service to monitor. For workloads under 5 million vectors, performance is more than adequate.
Your workload exceeds what a single Postgres instance handles comfortably (hundreds of millions of vectors, high concurrent query throughput, or requirements for auto-scaling and per-tenant isolation). Choose between:
You're prototyping, building local-first, or don't want to run a server. Chroma for the simplest API and getting started fast. LanceDB for larger-than-memory datasets with disk-based indexing.
| Consideration | Recommended Option |
|---|---|
| Already running Postgres, <5M vectors | pgvector |
| Zero operational overhead, any scale | Pinecone |
| Open-source, dedicated, self-hosted | Qdrant |
| Built-in vectorization, hybrid search | Weaviate |
| Billions of vectors, enterprise | Milvus |
| Prototyping, local dev, learning | Chroma |
| Embedded, local-first, edge | LanceDB |
For most teams adding AI features to an existing backend, pgvector is the simplest path. You avoid a separate service, get transactional consistency, and keep the SQL tooling you already know.
If you're building a TypeScript backend, Encore provisions PostgreSQL with pgvector automatically. Databases are declared in code, migrations run on startup, and the same setup works locally and in production:
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";
const db = new SQLDatabase("search", {
migrations: "./migrations",
});
export const search = api(
{ expose: true, method: "POST", path: "/search" },
async (req: { query: string }): Promise<{ results: SearchResult[] }> => {
const embedding = await generateEmbedding(req.query);
const rows = await db.query<SearchResult>`
SELECT id, title, 1 - (embedding <=> ${embedding}::vector) AS similarity
FROM documents
ORDER BY embedding <=> ${embedding}::vector
LIMIT 5
`;
const results: SearchResult[] = [];
for await (const row of rows) {
results.push(row);
}
return { results };
}
);
For a step-by-step tutorial building a complete RAG pipeline, see How to Build a RAG Pipeline with TypeScript. For a head-to-head comparison with the most popular managed alternative, see pgvector vs Pinecone.
Have questions about choosing a vector database? Join our Discord community where developers discuss architecture decisions daily.