Skip to content

About

One video intelligence app built three ways, on Pixeltable, Supabase and Convex. Every number measured, all three executed, tradeoffs stated.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Pixeltable vs Supabase vs Convex

CI

Three implementations of one application: a video intelligence pipeline that extracts frames, transcribes speech, embeds both, detects scenes, and answers questions about what it saw and heard.

Most stacks glue a blob store, a warehouse, a vector database, an orchestrator and custom endpoints together, and you pay for the joints. Pixeltable is the database, the orchestration and the serving: tables, computed columns, indexes and endpoints in one Python file. Insert a row. Transforms run.

Pixeltable sponsors this repo, so the methodology is written to be attacked: same contract, same fixtures, same models, every implementation held to its vendor's own checker in CI, and every number generated by harness/run_comparison.py from the source. n/a means a metric does not apply, never that it scored zero.

Pixeltable Supabase Convex
App code you maintain 123 306 426
Plus the shared compute service 0 278 278
Total 123 584 704
Files you open to read the backend 1 7 7
Schema objects 2 tables, 2 views 5 tables, 1 view, 3 FKs 5 tables
Vector indexes 2 2 2
Orchestration hops 2 13 9
HTTP routes with a hand-written handler 1 5 5

Benchmark summary: p50 latency by operation, effort to land a schema change, and the hosted-agent swap. Rendered from the committed artifacts by harness/render_summary.py.

Speed, on one laptop (docs/SCALE.md): Pixeltable is last on ingest and on search, and degrades most under eight concurrent clients; Convex is fastest on reads; on the agent query, with the chat model on the same GPU everywhere, Convex answers first and Pixeltable last. An earlier version of this repo reported Pixeltable far ahead on the agent. That was our compute service leaving the model on CPU (docs/device.json), not a platform difference.

Read docs/TRADEOFFS.md before the rest. This app is media-heavy, which suits Pixeltable; if you need realtime, row-level security or a managed database, the answer changes.

What the difference actually is

  • Media processing lives in a second service. Edge Functions' documented memory and CPU-time limits sit below what these models need, and Convex's default runtime exposes no subprocess; ffmpeg inside Convex's Node runtime was not attempted. So both use compute-service/, and three of its seven endpoints have no hosted-API substitute.
  • Adding a column to live data is 1 line against 24 and 41 (docs/EVOLVE.md); the backfill is fused into pxt schema update.
  • Processing fires for any writer, because the pipeline is the schema. On the other two it lives in the ingest path, so a row written by another client is not processed.
  • Retrieval knows its own model. Elsewhere you embed the query yourself and the dimension is the only guard.
  • Errors are per cell (errormsg, errortype); elsewhere a failed step marks the whole video status: 'error'.
  • Lineage is in the catalog (pxt columns, pxt dashboard); the other two record nothing to draw.
  • Request validation is derived: a bad body is a 422 on Pixeltable, against 28 and 42 hand-written lines.
  • A hosted-model swap is a 6-line schema change against 29 lines of retry/backoff (docs/hosted.json). On the paid endpoint all three answer 12/12; the free pool returns malformed 200 bodies (docs/hosted_probe.json), which a computed column evaluates to a null answer - 7/12 against 12/12 in the earlier run there.

Every implementation is held to its vendor's own checker

Checker What it gates
Supabase deno lint, supabase db advisors --local Edge Function style; no security or performance errors on a live database
Convex @convex-dev/eslint-plugin, tsc --noEmit Their own best-practice rules against real generated code
Pixeltable ruff Generic Python. Pixeltable ships no conformance checker, the weakest automated proof of the three.

ci.yml is the fast gate on every push; live.yml stands up all three plus the compute service and runs every suite in docs/METHODOLOGY.md against them.

The whole Pixeltable pipeline

class Videos(TableModel, name='videos'):
    video: pxt.Video
    title: pxt.String
    audio = extract_audio(video, format='mp3')
    duration_sec = pxtf.video.get_duration(video)
    scenes = video.scene_detect_content(threshold=8.0)

class Frames(TableModel, name='frames', base=Videos,
             iterator=frame_iterator(Videos.video, fps=1.0)):
    still = pxtf.image.resize(frame, (320, 180))
    __indexes__ = [pxt.EmbeddingIndex(frame, embedding=VISUAL)]

class Chunks(TableModel, name='chunks', base=Videos,
             iterator=audio_splitter(Videos.audio, duration=10.0)):
    transcript = transcribe(audio_segment, model='base.en').text.astype(pxt.String)
    __indexes__ = [pxt.EmbeddingIndex(transcript, embedding=SEMANTIC)]

The whole thing is pixeltable/app.py: 129 lines, HTTP included.

Run it

Everything runs locally on CPU, no API key.

pip install gTTS && python fixtures/videos/generate.py
cd pixeltable && pip install -e . && pxt init
pxt schema update app.py media    # creates the tables
pxt service update app.py media   # starts HTTP
URL=$(pxt service list | awk '/^media/{print $2}')

Supabase and Convex need compute-service/ first (cd compute-service && pip install -e . && uvicorn app:app --host 0.0.0.0 --port 9000 --timeout-keep-alive 120; Supabase reaches it from inside a container, and app.py says why keep-alive is set), then supabase-app/README.md or convex-app/README.md. Convex picks its ports at startup; npx convex dev writes CONVEX_SITE_URL into convex-app/.env.local.

Measure and test

SUPA=http://127.0.0.1:54321        # supabase status
CONVEX=http://127.0.0.1:3211       # CONVEX_SITE_URL in convex-app/.env.local
SECRET=...                         # supabase status, the Edge Function needs it

python harness/run_comparison.py   # regenerates docs/metrics.json; CI fails on drift
python harness/check_docs.py       # fails if the docs stop quoting the artifacts

python harness/seed.py --impl pixeltable
python harness/seed.py --impl supabase --base-url $SUPA --auth-token $SECRET
python harness/seed.py --impl convex --base-url $CONVEX

pytest harness/test_equivalence.py --impl pixeltable
pytest harness/test_differential.py harness/test_resilience.py \
  --compare pixeltable --compare supabase=$SUPA --compare convex=$CONVEX \
  --auth-token $SECRET
pytest harness/test_metrics.py     # tests the measuring code itself

python fixtures/videos/generate.py --tier large
python harness/benchmark.py --impl pixeltable --tier large      # docs/SCALE.md
python harness/bench_evolve.py --supabase-token $SECRET         # docs/EVOLVE.md
# run compute-service on :9100 first; this script's proxy takes its usual :9000
python harness/bench_roundtrip.py --impl supabase --base-url $SUPA --auth-token $SECRET
python harness/bench_roundtrip.py --impl convex --base-url $CONVEX --add-latency-ms 80  # docs/roundtrip.json
OPENROUTER_API_KEY=sk-or-... python harness/bench_hosted.py --supabase-token $SECRET

test_recovery.py writes and needs --destructive; re-seed afterwards.

Docs

Contributing

See CONTRIBUTING.md. Corrections that shrink the gap get published.

Pixeltable

License

Apache 2.0

About

One video intelligence app built three ways, on Pixeltable, Supabase and Convex. Every number measured, all three executed, tradeoffs stated.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages