What is a vector database?
A vector database stores embeddings and enables fast approximate nearest-neighbour search - finding the most semantically similar items to a query vector at scale.
Overview
Key Points
- •Core operation: given a query vector, return the top-K vectors with the smallest distance (cosine or dot product similarity).
- •All vector databases support metadata filtering: "find the top-5 most similar chunks where `source = 'policy.pdf'`".
- •HNSW (Hierarchical Navigable Small World) is the most common index algorithm - fast approximate search with high recall.
- •Popular options: **Pinecone** (managed cloud), **pgvector** (PostgreSQL extension), **Chroma** (local/OSS), **Weaviate**, **Qdrant**, **Milvus**.
- •For small datasets (<100k vectors), an in-memory search over all vectors is often fast enough - no vector DB needed.
- •Vector DBs are not a replacement for regular databases - use both together: metadata in SQL, vectors in a vector index.
Examples
pgvector - vector search inside PostgreSQL
sql-- Enable the extension
CREATE EXTENSION IF NOT EXISTS vector;
-- Create a table with a vector column (1536 dims for text-embedding-3-small)
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
source TEXT,
embedding vector(1536)
);
-- Create an HNSW index for fast approximate nearest-neighbour search
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
-- Insert a document with its embedding
INSERT INTO documents (content, source, embedding)
VALUES ('Refunds are processed within 5–7 business days.', 'policy.pdf', '[0.12, -0.04, ...]');
-- Find the 5 most similar documents to a query embedding
SELECT content, source,
1 - (embedding <=> '[0.11, -0.03, ...]') AS similarity
FROM documents
WHERE source = 'policy.pdf' -- metadata filter
ORDER BY embedding <=> '[0.11, -0.03, ...]' -- cosine distance
LIMIT 5;<=> is cosine distance. Use <-> for L2 (Euclidean). Both operators use the HNSW index.
Pinecone - managed vector database
typescriptimport { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY! });
const index = pc.index('my-docs');
// Upsert vectors with metadata
await index.upsert([
{
id: 'chunk-1',
values: embeddingArray, // number[] with 1536 elements
metadata: { text: chunk, source: 'faq.pdf', page: 3 },
},
]);
// Query: top-5 nearest neighbours, filtered by metadata
const result = await index.query({
vector: queryEmbedding,
topK: 5,
includeMetadata: true,
filter: { source: { $eq: 'faq.pdf' } },
});
const retrievedChunks = result.matches.map(m => m.metadata!.text as string);Chroma - local/embedded vector store (great for dev/testing)
pythonimport chromadb
client = chromadb.Client() # in-memory; use chromadb.PersistentClient(path) for disk
collection = client.create_collection('docs')
# Add documents (Chroma embeds them for you if you configure an embedding function)
collection.add(
documents=['Our refund policy is 30 days.', 'Contact support at help@example.com'],
ids=['doc-1', 'doc-2'],
metadatas=[{'source': 'policy'}, {'source': 'contact'}]
)
# Query
results = collection.query(
query_texts=['How do I get my money back?'],
n_results=2
)
print(results['documents']) # [['Our refund policy is 30 days.', ...]]Pro Tip
If you already use PostgreSQL, start with **pgvector** - it means one less service to manage. For document counts under ~1M, pgvector with an HNSW index is fast enough for production. Only consider a dedicated vector database (Pinecone, Weaviate) when you need multi-tenant isolation, billion-scale search, or built-in replication that your Postgres setup cannot easily provide.