Pixeltable and Modal
Modal is a serverless compute engine for Python: launch GPU containers in seconds, run distributed batch jobs, and scale from zero to thousands of containers with zero Kubernetes boilerplate. Pixeltable is an AI data infrastructure engine: declare schemas with multimodal columns, automatic transformation DAGs, and persistent embedding indexes. They are complementary: pick Modal when you need raw elastic GPU compute. Pick Pixeltable when your data needs persistent state, incremental lineage, and declarative pipelines.
pip install 'pixeltable[serve]'Elastic compute vs persistent dataflow
| Side | Pixeltable | Modal |
|---|---|---|
| At a glance |
|
|
What each actually owns
Modal wins serverless container scaling, cold-start speed, and on-demand GPU infrastructure. Pixeltable wins persistent schema definitions, incremental DAG recomputation, and automated vector indexing. Many teams use Modal to execute heavy GPU models wrapped as Pixeltable UDFs.
| Feature | Pixeltable | Modal |
|---|---|---|
| Core capability | Persistent state + DAG transformation engine + API serving | Stateless serverless compute & elastic GPU container runner |
| GPU infrastructure & scaling | Configured runner environment or managed cloud instances | Elastic on-demand GPU allocation (T4, A10G, A100, H100) with per-second billing |
| Cold start & burst scaling | Always-on daemon or worker process | Sub-second container startup; scales to thousands of concurrent containers |
| Persistent table schema & lineage | Native tables, cell-level error tracking, and immutable data versioning | Stateless functions; requires external database (Postgres, S3, DynamoDB) |
| Incremental DAG recomputation | Engine understands row dependency graph; backfills only deltas | You orchestrate re-runs and handle idempotency manually in function code |
| Vector index maintenance | EmbeddingIndex is declared on the table and updates on insert | Functions compute vectors, but you must upsert into external vector DB |
| Multimodal type system | Native pxt.Image, pxt.Video, pxt.Audio with automatic decoding & caching | Standard Python objects (PIL.Image, bytes) passed via network serialization |
| Free plan tier | Community tier: free hosted compute + managed catalog + 50 GB media storage and 10 GB database storage | $30/month recurring free compute credits for CPU and GPU instances |
Video frame extraction & scene search
Pixeltable: Video decoding and CLIP embedding are declared in the schema. Modal: Excellent for running heavy GPU inference, but requires external orchestration and storage to persist results.
Pixeltable
import pixeltable as pxtfrom pixeltable.functions.video import frame_iteratorfrom pixeltable.functions.huggingface import clipTableModel = pxt.model_base()clip_embed = clip.using(model_id='openai/clip-vit-base-patch32')class Videos(TableModel, name='videos'):video: pxt.Videotitle: pxt.Stringclass Frames(TableModel,name='frames',base=Videos,iterator=frame_iterator(Videos.video, fps=1),):__indexes__ = [pxt.EmbeddingIndex(frame, image_embed=clip_embed)]# pxt schema update app.py mediavideos = pxt.get_table('media.videos')videos.insert([{'video': 'lecture.mp4', 'title': 'Machine Learning 101'}])# Query frames semantically across all stored videosframes = pxt.get_table('media.frames')sim = frames.frame.similarity(string='whiteboard diagram')hits = frames.order_by(sim, asc=False).limit(5).select(frames.pos, frames.title)
Modal
import modalapp = modal.App("video-processor")image = modal.Image.debian_slim().pip_install("torch", "transformers", "opencv-python", "pillow")@app.function(image=image, gpu="T4", timeout=600)def process_video_frames(video_url: str):import cv2from PIL import Imagefrom transformers import CLIPProcessor, CLIPModel# 1. Download and extract frames using OpenCVcap = cv2.VideoCapture(video_url)frames = []# ... frame extraction logic ...# 2. Run CLIP inference on GPUmodel = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").cuda()processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")# ... compute embeddings ...# 3. Must save results to external database# db.insert_many(...)return {"status": "ok", "frames_processed": len(frames)}# Modal handles GPU execution, but you must build the storage and query layer.
Complementary: Delegating heavy GPU UDFs from Pixeltable to Modal
You can use Modal as the remote GPU compute backend for a Pixeltable UDF, combining declarative state with elastic GPU execution.
Pixeltable
import pixeltable as pxtimport modal# Reference a Modal functionrun_flux = modal.Function.lookup("image-gen", "generate_flux_image")@pxt.udfdef modal_generate(prompt: str):# Executes remotely on a Modal A100 GPU. The UDF returns a PIL image.import iofrom PIL import Imageimage_bytes = run_flux.remote(prompt)return Image.open(io.BytesIO(image_bytes))TableModel = pxt.model_base()class Prompts(TableModel, name='prompts'):prompt: pxt.Stringgenerated_image = modal_generate(prompt)# Inserting a row triggers remote Modal GPU execution,# and Pixeltable stores and versions the resulting image.
Modal
# In modal_app.pyimport modalapp = modal.App("image-gen")image = modal.Image.debian_slim().pip_install("diffusers", "torch")@app.function(image=image, gpu="A100")def generate_flux_image(prompt: str) -> bytes:# Runs on Modal's A100 GPU infrastructurefrom diffusers import FluxPipelineimport iopipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-schnell", torch_dtype=torch.bfloat16).to("cuda")out = pipe(prompt, num_inference_steps=4).images[0]buf = io.BytesIO()out.save(buf, format="PNG")return buf.getvalue()
When to choose which platform
Use Pixeltable when
- You need persistent data schemas and versioning
When your multimodal assets (video, audio, text) require persistent indexing, data lineage, and incremental schema backfills.
- You want end-to-end API serving in one file
Declare tables, computed transformations, and FastAPIRouter endpoints in a single Python application.
- You want automated vector index synchronization
Embedding indexes stay synchronized with source data on every insert, update, and delete without external worker scripts.
Use Modal when
- You need massive elastic GPU compute on demand
Modal provisions T4, A10G, A100, and H100 GPUs in seconds with per-second billing, scaling to hundreds of workers during batch bursts.
- You are running standalone heavy ML batch jobs
Training runs, fine-tuning jobs, distributed web scraping, or massive one-off batch transformations defined in pure Python.
- You want $30/month in free compute credits
Modal provides generous recurring monthly credits that cover substantial experimentation and lightweight production workloads.
Making the right choice
Combining Modal and Pixeltable
- Modal is not a database, and Pixeltable is not a general-purpose serverless container orchestrator. They work exceptionally well together.
- Use Pixeltable as the system of record for multimodal data, computed columns, and embedding indexes.
- Wrap Modal functions inside Pixeltable `@pxt.udf` decorators when specific transformation steps require specialized GPU hardware.
Frequently asked questions
More comparisons
- Three-way compare: Pixeltable vs Supabase vs Convex
- Cloud DB & Compute Shootout (11 Providers)
- Pixeltable vs Neon
- Pixeltable vs Supabase
- Pixeltable vs Prisma Postgres
- Pixeltable vs Turso
- Pixeltable vs Convex
- Pixeltable vs Cloudflare
- Pixeltable vs Cohesivity
- Pixeltable vs LangChain
- Pixeltable vs LanceDB
- Pixeltable vs Pinecone
- Pixeltable vs Label Studio
- Pixeltable vs Voxel51
State and compute unified. Or scale compute with Modal.
Declare tables and computed columns in app.py. Apply with pxt schema update. Run transforms locally or delegate heavy steps to Modal.