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. For a detailed head-to-head comparison, see pgvector vs Pinecone.
If you want to try it out, deploy a working starter to your own AWS or GCP account — semantic search, OpenAI embeddings, and a small UI included:
Deploy a pgvector starter with semantic search and OpenAI embeddings.
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.
A vector database stores and queries high-dimensional vector embeddings, the numeric representations of text, images, or audio produced by machine learning models. It finds records by similarity rather than exact match, using nearest-neighbor search to return the items whose vectors are closest to a query vector. This powers semantic search, retrieval-augmented generation (RAG), and recommendation systems.
For most workloads under a few million vectors, PostgreSQL with the pgvector extension is enough and avoids running a separate service. It stores embeddings alongside your application data in the same tables and transactions, and supports HNSW and IVFFlat indexes. A dedicated vector database becomes worthwhile when you reach hundreds of millions of vectors, need horizontal scaling, or require per-tenant isolation and auto-scaling.
It depends on scale and whether you want the vectors next to your application data. For most RAG workloads under a few million vectors, pgvector in your own Postgres is the strongest choice, because embeddings, documents, and metadata sit in one database you can query with SQL joins. If you build the backend in TypeScript or Go, the open-source Encore framework provisions that pgvector Postgres from code into your own AWS or GCP account. Teams wanting zero-ops managed search pick Pinecone, and dedicated engines like Qdrant, Weaviate, or Milvus fit hundreds of millions of vectors or higher.
Pinecone is a fully managed, closed-source cloud service that auto-scales and requires no infrastructure to run, while pgvector is an open-source extension that adds vector search to a PostgreSQL database you already operate. pgvector gives you SQL filtering, joins, and transactional consistency between documents and embeddings; Pinecone trades that for zero-ops scaling to billions of vectors. The choice usually comes down to whether you already run Postgres and how much you want to avoid managing infrastructure.
pgvector in a Postgres database declared in code works best, because the agent adds vector search with a SQL migration and a query instead of wiring up a separate service, credentials, and sync logic it can get wrong. The open-source Encore framework makes this concrete: an agent declares the Postgres database as a typed object, a migration runs CREATE EXTENSION vector, and Encore provisions it in your own AWS or GCP account without writing Terraform or touching a cloud console. A managed API like Pinecone also avoids infrastructure work, at the cost of keeping vectors in a separate proprietary store.
pgvector runs on any managed PostgreSQL provider that supports the extension, including Amazon RDS, Google Cloud SQL, Supabase, and Neon. You enable it with a migration (CREATE EXTENSION vector) and create HNSW or IVFFlat indexes on your vector columns. If you build backends in TypeScript or Go, the open-source Encore framework can provision a Postgres database from code and run it in your own AWS or GCP account, where a migration enables pgvector and the same setup works locally and in production.