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]'
See how it works

Elastic compute vs persistent dataflow

SidePixeltableModal
At a glance
  • Persistent application schema with native multimodal types (Video, Audio, Image, Document)
  • Computed columns execute transformations automatically upon row insertion
  • Incremental computation: changing a model or column recomputes only affected rows
  • EmbeddingIndex maintains vector search indexes in-engine without external synchronizers
  • Serverless Python container execution with sub-second cold starts and rapid scaling
  • On-demand access to GPUs (T4, A10G, A100, H100) with per-second billing and zero idle cost
  • Pure Python infrastructure definitions: images, secrets, network mounts, and scheduled cron jobs
  • Stateless compute engine: requires external databases and object stores for long-term state

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.

FeaturePixeltableModal
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 pxt
from pixeltable.functions.video import frame_iterator
from pixeltable.functions.huggingface import clip
TableModel = pxt.model_base()
clip_embed = clip.using(model_id='openai/clip-vit-base-patch32')
class Videos(TableModel, name='videos'):
video: pxt.Video
title: pxt.String
class 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 media
videos = pxt.get_table('media.videos')
videos.insert([{'video': 'lecture.mp4', 'title': 'Machine Learning 101'}])
# Query frames semantically across all stored videos
frames = 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 modal
app = 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 cv2
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
# 1. Download and extract frames using OpenCV
cap = cv2.VideoCapture(video_url)
frames = []
# ... frame extraction logic ...
# 2. Run CLIP inference on GPU
model = 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 pxt
import modal
# Reference a Modal function
run_flux = modal.Function.lookup("image-gen", "generate_flux_image")
@pxt.udf
def modal_generate(prompt: str):
# Executes remotely on a Modal A100 GPU. The UDF returns a PIL image.
import io
from PIL import Image
image_bytes = run_flux.remote(prompt)
return Image.open(io.BytesIO(image_bytes))
TableModel = pxt.model_base()
class Prompts(TableModel, name='prompts'):
prompt: pxt.String
generated_image = modal_generate(prompt)
# Inserting a row triggers remote Modal GPU execution,
# and Pixeltable stores and versions the resulting image.

Modal

# In modal_app.py
import modal
app = 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 infrastructure
from diffusers import FluxPipeline
import io
pipe = 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

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.

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