Pixeltable and pgvector

Updated

Which is better, Pixeltable or pgvector?

It depends. Pixeltable belongs when media, computed columns, and an embedding index should live on the source row and stay current on insert. pgvector belongs when you already run Postgres, want SQL joins and ACID around vectors, or need HNSW or IVFFlat you tune yourself. Pixeltable is not a vector database. Keep pgvector in the database you already operate. As of 2026-10-28.

pgvector is a Postgres extension for vector similarity search: a vector column, L2, inner-product, or cosine operators, and HNSW or IVFFlat indexes. Pixeltable is not a vector database. It is the application schema around one: typed media, computed columns, EmbeddingIndex, and HTTP in one Python file. Keep pgvector in the Postgres you already operate; use Pixeltable when the pipeline around the vector is the product.

pip install 'pixeltable[serve]'
See how it works

The index in Postgres vs the pipeline around it

SidePixeltablepgvector
At a glance
  • Chunking, embeddings, and similarity live on the table
  • Insert and delete keep the index current, no upsert job
  • Source media stays queryable next to the vector
  • HTTP from the same file if you declare FastAPIRouter
  • vector, halfvec, bit, and sparsevec types in Postgres you already run
  • Exact search, or HNSW or IVFFlat approximate indexes you tune
  • JOINs, ACID, point-in-time recovery, any Postgres client
  • You still generate embeddings, chunk files, and serve HTTP yourself

What each actually owns

pgvector wins SQL joins, ACID, and ANN you tune inside Postgres. Pixeltable wins insert-triggered media pipelines and an index declared on the source row. Last reviewed: Oct 2026. Sources: github.com/pgvector/pgvector (README), github.com/pixeltable/showcase-call-intelligence/blob/main/compare/WHY_PIXELTABLE.md.

FeaturePixeltablepgvector
What it is
Tables + computed columns + EmbeddingIndex
Postgres extension for vector similarity search
Keeping vectors in sync
Index is schema; insert, delete, and update recompute the affected rows
You embed and INSERT or UPDATE; a failed embed job is a row you repair
Source media
Document, Image, Video, Audio columns next to the index
bytea, text, or a URL you store; bytes live in S3 or on disk unless you add that
SQL and ACID
Catalog on Postgres; you do not write the JOIN or the HNSW DDL
Native SQL, JOINs, transactions, backups, extensions you already operate
ANN inside Postgres
EmbeddingIndex on the catalog; not HNSW or IVFFlat you tune with lists and probes
HNSW or IVFFlat, m, ef_construction, probes, exact search with no index
Glue around it
One schema
Chunker + embedder + orchestrator + FastAPI, unless you already have them
Ops you already know
pxt schema update and pxt service update; a different operational model
CREATE EXTENSION vector; the Postgres you already back up

Document search

Pixeltable: document_splitter view and EmbeddingIndex. Query with similarity(string=), then order_by. Apply with pxt schema update app.py search. pgvector: CREATE EXTENSION, a vector column, HNSW, ORDER BY embedding <-> query. From github.com/pgvector/pgvector (accessed 2026-10-28). You still embed the document and the query yourself.

Pixeltable

import pixeltable as pxt
from pixeltable.functions.document import document_splitter
from pixeltable.functions.huggingface import sentence_transformer
TableModel = pxt.model_base()
embed = sentence_transformer.using(
model_id='sentence-transformers/all-MiniLM-L6-v2'
)
class Docs(TableModel, name='docs'):
document: pxt.Document
title: pxt.String
class Chunks(
TableModel,
name='chunks',
base=Docs,
iterator=document_splitter(
Docs.document, separators='sentence,token_limit', limit=512
),
):
__indexes__ = [pxt.EmbeddingIndex(text, embedding=embed)]
if __name__ == '__main__':
# After: pxt schema update app.py search
docs = pxt.get_table('search.docs')
docs.insert([{'document': 'papers/ml.pdf', 'title': 'Research Paper'}])
chunks = pxt.get_table('search.chunks')
sim = chunks.text.similarity(string='machine learning algorithms')
chunks.order_by(sim, asc=False).limit(10).select(chunks.text, chunks.title)

pgvector

-- github.com/pgvector/pgvector
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE items (
id bigserial PRIMARY KEY,
title text,
embedding vector(384)
);
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
-- You still chunk the PDF and call an embedder in application code.
INSERT INTO items (title, embedding) VALUES (
'Research Paper',
'[0.1, 0.2, ...]'
);
SELECT id, title
FROM items
ORDER BY embedding <-> '[0.11, 0.19, ...]'
LIMIT 10;

When each belongs

Use Pixeltable when

  • RAG where the source row matters

    Documents, images, or video plus the embedding. Insert should update the index. You do not want a second upsert path beside Postgres.

  • You were about to glue Celery, Redis, and pgvector for a media app

    The call-intelligence showcase on GitHub measures that glue: 1,171 lines in 24 files for FastAPI + SQLAlchemy + Alembic + Celery + Redis + Postgres + pgvector, against 680 lines in 4 files for Pixeltable (compare/WHY_PIXELTABLE.md on main, accessed 2026-10-28). Line counts, not query latency.

Use pgvector when

  • Vectors belong in the Postgres you already run

    JOINs, ACID, backups, RLS, a client every language already has. Pixeltable does not replace Postgres for that job. README: github.com/pgvector/pgvector

  • ANN you tune is the binding constraint

    HNSW vs IVFFlat, lists, probes, ef_search, halfvec. This page does not claim Pixeltable wins a recall/latency bake-off. pgvector publishes those knobs; we did not rerun them.

Making the right choice

  • Do not over-claim

    • Pixeltable is not a vector database and not a Postgres replacement.
    • The showcase numbers are source line counts and operator steps from a published methodology, not ANN latency. How to rerun: github.com/pixeltable/showcase-call-intelligence (METHODOLOGY.md). We did not rerun it in this change.
    • That same page says where the Reference (pgvector) is ahead: Celery can process calls in parallel; a Pixeltable insert holds the table lock, so inserts into one table run one at a time. Status during processing is also more visible on the Reference.
    • No Pixeltable vs pgvector query-latency benchmark is on this page.
    • Supabase, Neon, and Prisma compare pages cover hosted Postgres. This page is the extension.

Frequently asked questions

Is Pixeltable a pgvector alternative?

For app-scale RAG where the source row matters, it can replace the glue around pgvector (chunking, embed jobs, HTTP). It does not replace pgvector inside Postgres. Keep pgvector when SQL, JOINs, and HNSW you tune are the product.

Is Pixeltable a vector database?

No. EmbeddingIndex is declared on a table that also holds source media and computed columns. pgvector is the vector type and the ANN index in Postgres. Different layer.

Can I use Pixeltable with pgvector?

Yes. Pixeltable can remain the system of record; export embeddings if pgvector is already the serving contract in your database. Complementary, not a requirement.

What about Neon, Supabase, and Pinecone?

Neon and Supabase are hosted Postgres (they can run pgvector). Pinecone is a managed ANN service. This page is the extension. See /compare/pixeltable-vs-neon, /compare/pixeltable-vs-supabase, and /compare/pixeltable-vs-pinecone.

Index on the row. Keep Postgres when SQL is the product.

Declare tables and EmbeddingIndex in app.py. Apply with pxt schema update. Keep pgvector when vectors should live next to the relational rows you already query.

pip install 'pixeltable[serve]'
See how it worksGet expert guidance