Retrieval

Do I need a vector database if I use Postgres?

You need a separate vector database only if nearest-neighbor search cannot live in Postgres. pgvector stores vectors on the same row and answers similarity in SQL. A dedicated engine is for filtered ANN at scale, or for blobs SQL was not built to serve. Many apps stay on Postgres plus an embed job they already run.

Updated · Part of How does an embedding index differ from a vector database?

Short answer

Usually no. If Postgres already holds the application row, pgvector adds a vector column, exact search, and HNSW or IVFFlat indexes so nearest neighbors are a SQL query. You still compute embeddings in a worker you write, and media bytes usually live in object storage. A second database is optional until that shape breaks.

What pgvector actually is

pgvector is open-source vector similarity search for Postgres: a vector type, L2 / inner product / cosine distance, and optional HNSW or IVFFlat indexes. Filters and joins use the rest of the SQL row. Any host that runs the extension (self-managed Postgres, Supabase, Neon, and others) can serve it. It is not a multimodal lake and not a dedicated ANN cluster. Repo: https://github.com/pgvector/pgvector

When a dedicated vector database still wins

A dedicated engine is the better fit when the serving contract is filtered ANN as a service, not SQL next to the row.

  • Qdrant when payload indexes on HNSW, dense and sparse vectors, and a Rust engine you can shard are the product. Docs: https://qdrant.tech/documentation/overview/
  • LanceDB when images, video, audio, text, and embeddings should share one Lance table, embedded or as a lakehouse. Docs: https://docs.lancedb.com/
  • Pinecone, Weaviate, or Milvus when that vendor query API, hybrid BM25 fusion, or a scale-out cluster is already the contract.
  • Stay on pgvector when the vector count and QPS fit one Postgres instance and SQL joins are how you filter.

How to choose

Start from the system of record, not from a latency bake-off this page did not run.

  • If the source of truth is a Postgres row, try pgvector first.
  • If the source of truth is a Lance table or a dedicated ANN service, pick that engine and keep Postgres for the parts that are SQL.
  • If the source of truth is the passage, frame, or file, declare the index on that table so insert keeps it current. That is not pgvector and not a second database.

Last reviewed

Facts on this page were checked against vendor documentation on 2026-10-28. Product surfaces move; treat version names and APIs as directional and follow the official links in Related.

Postgres versus a vector database (last reviewed: Oct 2026)

Postgres versus a vector database (last reviewed: Oct 2026)
ApproachWhere vectors liveFiltersWhen it is enough
Postgres onlyNowhere; you have no ANNSQL on scalarsNo similarity search needed
Postgres plus pgvectorA vector column on the same rowSQL WHERE plus distanceThe row is already in Postgres and one instance holds the vectors
Dedicated vector DB (Qdrant, Pinecone, Weaviate, Milvus)Points or objects in that enginePayload or metadata filters on the ANN graphFiltered ANN, sharding, or a vendor query SLA is the contract
LanceDBThe same Lance table as blobs and featuresSQL-style filters, FTS, hybrid (vendor docs)Multimodal lake layout is the product
Index on the source tableOn the passage, frame, or file rowwhere() on that table plus similarity()Insert should embed and the media is typed columns, not a SQL row you already have

Where Pixeltable fits

Use Pixeltable when the system of record is the passage, frame, or file, not a Postgres row you already join: declare pxt.EmbeddingIndex, query with column.similarity(string=...), and insert keeps the index current. Pixeltable is not pgvector and not a drop-in Qdrant cluster. Keep pgvector when Postgres already holds the row and you will embed in a worker you write. Keep Qdrant, Pinecone, Weaviate, or Milvus when that engine is the serving contract. Keep LanceDB when Lance layout is the product. A product list is pgvector vs Qdrant vs LanceDB.

import pixeltable as pxt
from pixeltable.functions.huggingface import sentence_transformer
TableModel = pxt.model_base()
embed = sentence_transformer.using(
model_id='sentence-transformers/all-MiniLM-L6-v2'
)
class Passages(TableModel, name='passages'):
text: pxt.String
source: pxt.String
__indexes__ = [
pxt.EmbeddingIndex(text, string_embed=embed),
]
@pxt.query
def search_passages(query: str, limit: int = 5):
sim = Passages.text.similarity(string=query)
return (
Passages.order_by(sim, asc=False)
.limit(limit)
.select(Passages.text, Passages.source, sim)
)

Questions

Is pgvector a vector database?

It is a Postgres extension that stores vectors and answers nearest-neighbor queries. It is not a separate database process. Teams still call the wider category "a vector database" in conversation; the ops story is Postgres.

When is pgvector not enough?

When you need a dedicated ANN service with payload filters and sharding, hybrid BM25 fusion as the product, or multimodal blobs in a Lance table. Official pgvector scope is SQL next to the row: https://github.com/pgvector/pgvector

Does Postgres store the video files?

Usually no. pgvector stores vectors. Bytes typically live in object storage with a URL or id on the SQL row. A typed Video column is a different schema.

Do I still have to embed myself?

Yes for pgvector. Dedicated engines also need embeddings unless you add their inference product. An EmbeddingIndex on a source table embeds on insert as part of the schema.

Next step

Install the Pixeltable skill, or sign up for Cloud and run the same file on a hosted database.