A vector database stores embeddings, which are lists of numbers that represent the meaning of text, images or other data, and answers one question fast: which stored vectors are closest to this query vector? That makes it the search layer behind semantic search and retrieval-augmented generation (RAG), where "closest" means "most similar in meaning", not "shares the same keywords".
The "database" part is ordinary: rows, IDs, metadata, filters. What's special is the index that finds nearest neighbours among millions of high-dimensional vectors without comparing against every one.
What an embedding is
An embedding model turns an input into a fixed-length list of numbers. Inputs with similar meaning end up close together in that space. As of October 2026, OpenAI's docs state that the vector length "is 1536 for text-embedding-3-small" and 3,072 for text-embedding-3-large.
That is the property a good embedding model is trained for: "How do I reset my password?" and "I forgot my login credentials" should land near each other even though they share almost no words, while "Shipping times to Canada" should land far away. A keyword search can't make that connection, because it only compares the words themselves.
How similarity search works
To search, you embed the query with the same model, then ask for the stored vectors nearest to it. "Nearest" is a distance function:
| Metric | What it measures | pgvector operator |
|---|---|---|
| Cosine distance | Angle between vectors, ignoring length | <=> |
| L2 (Euclidean) distance | Straight-line distance | <-> |
| Inner product | Dot product (pgvector returns it negated, so smaller is closer) | <#> |
| L1 distance | Sum of absolute differences | <+> |
Which one to use depends on the model; its documentation will say. OpenAI recommends cosine similarity and notes its embeddings "are normalized to length 1", which means cosine similarity and dot product give the same ranking, and Euclidean distance does too.
A tiny worked example in two dimensions: query [1, 0], document A [0.8, 0.6], document B [0, 1]. All three have length 1. The dot products are 0.8 for A and 0 for B, so A is the nearer match. Real embeddings do the same arithmetic over 1,536 numbers instead of 2.
Why you need an index: exact vs approximate search
The simple way is to compute the distance to every stored vector and sort. That is exact, and pgvector does this by default: "By default, pgvector performs exact nearest neighbor search, which provides perfect recall." The cost grows with every row you add, and each comparison is over hundreds or thousands of dimensions.
Approximate nearest neighbour (ANN) indexes make search fast by not checking everything. pgvector's docs describe the trade honestly: an index gives "approximate nearest neighbor search, which trades some recall for speed." Recall here means the fraction of the true nearest neighbours the search actually returns.
HNSW
A widely used ANN index is HNSW (Hierarchical Navigable Small World), introduced by Malkov and Yashunin. It builds layered graphs linking each vector to some of its neighbours. A search starts in a sparse top layer, hops towards the query, and drops down into denser layers to refine. The paper reports that this layered approach gives "logarithmic complexity scaling" of search. pgvector's docs sum up the trade-off against IVFFlat: HNSW "has better query performance than IVFFlat (in terms of speed-recall tradeoff), but has slower build times and uses more memory."
IVFFlat
pgvector describes IVFFlat this way: it "divides vectors into lists, and then searches a subset of those lists that are closest to the query vector." You choose the number of lists when creating the index (WITH (lists = 100) in its example). Because the lists are learned from the data, pgvector advises creating an IVFFlat index only after the table has some data; HNSW has no such training step.
A vector search example with pgvector
You don't need a separate product to try this. pgvector adds vectors to PostgreSQL. Using the README's own example, with three-dimensional vectors so it fits on screen:
CREATE EXTENSION vector;
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
-- five nearest rows by L2 distance
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
-- add an approximate index for cosine distance
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
In a real app the column would be vector(1536), you'd store the text and metadata alongside it, and the query vector would come from the same embedding model. The index's operator class has to match the operator you query with: vector_cosine_ops serves <=>, vector_l2_ops serves <->.
Limits to know as of October 2026: pgvector columns hold up to 16,000 dimensions, but HNSW and IVFFlat index the vector type only up to 2,000 dimensions (halfvec up to 4,000).
Vector databases and RAG
The most common use today is retrieval-augmented generation. The idea comes from Lewis et al. (2020), who paired a language model's "parametric memory" (what it learned in training) with a "non-parametric memory" it can look things up in. A RAG pipeline works like this:
- Split your documents into chunks and embed each chunk. Store vectors plus the chunk text in the vector database.
- When a user asks a question, embed the question.
- Retrieve the nearest chunks.
- Put those chunks into the prompt and ask the model to answer from them.
OpenAI's embeddings guide describes the motivation: supplying the facts through search instead of putting all your information in the context window, which raises token costs. For how RAG compares with training the model on your data instead, see fine-tuning vs RAG.
Do you need a dedicated vector database?
| Option | Good fit when | Watch out for |
|---|---|---|
| No index, exact search (in memory or SQL) | Small collections; perfect recall matters most | Query time grows with row count |
| Extension in your existing database (pgvector) | You already run PostgreSQL; you want filters and joins in SQL | Index tuning and memory sit on your main database |
| Dedicated vector database or managed service | Very large collections, high query rates, vector search as a core product feature | Another system to run, sync and pay for |
There is no universal row count where exact search becomes too slow; it depends on dimensions, hardware and how fast answers must be. Measure query time on your own data before adding infrastructure.
If search results look wrong
Check the boring causes first. Every vector in the table and the query must come from the same embedding model and version; vectors from two models are not comparable. The query operator must match the index's operator class, or the index isn't used. Compare a few queries against exact search (drop or bypass the index) to see whether the approximate index is losing recall. And look at your chunks: a passage split across two chunks may match neither well. Retrieved text also costs tokens when it goes into a prompt; what a context window is explains the limit it counts against.
Frequently asked questions
- Is a vector database the same as an embedding?
- No. An embedding is the vector itself: a list of numbers an embedding model produces for a piece of text, an image or another item. A vector database is where you store many of those vectors, along with the original content and metadata, so you can quickly find the ones closest to a new query vector.
- Can I use PostgreSQL as a vector database?
- Yes. The pgvector extension adds a vector column type, distance operators and HNSW and IVFFlat indexes to PostgreSQL. You enable it with CREATE EXTENSION vector; and query with ORDER BY embedding <=> query LIMIT k. It keeps vectors next to your ordinary tables, so you can filter and join in one SQL query.
- Why did my vector search miss an obvious match?
- Approximate indexes such as HNSW trade some recall for speed, so a close match can occasionally be skipped. Other common causes are mixing embeddings from different models, comparing with a different distance metric than the index was built for, or chunks that split the relevant passage in two. Test against an exact search on a sample to see which one it is.
- How many dimensions should my vectors have?
- The embedding model decides. OpenAI's text-embedding-3-small returns 1,536 dimensions by default and text-embedding-3-large 3,072, and both accept a dimensions parameter to return shorter vectors at some cost in accuracy. Your database column and index must match whatever length you choose; pgvector indexes the vector type up to 2,000 dimensions.
Sources
- pgvector: open-source vector similarity search for Postgres
- OpenAI API docs: Vector embeddings
- Malkov and Yashunin: Efficient and robust approximate nearest neighbor search using HNSW graphs (arXiv:1603.09320)
- Lewis et al.: Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (arXiv:2005.11401)