All Stories
2026-10-20•12 min read

Pixeltable Cloud · TableModel · Computed Columns · Multimodal AI · Deployment · AI Agents

What Is Pixeltable? One app.py, Local to Cloud to Day 2

Pixeltable puts the multimodal database, orchestration, vector index, and HTTP serving in one app.py. Two commands apply it on your laptop, three put the same file on Pixeltable Cloud, and after that a change costs an upload, a rebuild, or a restart.

Pierre Brunelle

Pierre Brunelle

Pixeltable Team

View as Markdown

Summary: Pixeltable puts four systems in one Python file. Tables hold images, video, audio, and documents. Computed columns are the orchestration. An embedding index is a declaration on the table, and an HTTP route is a declaration over its columns. pxt schema update creates the tables, pxt service update serves the routes, and the same app.py runs on Pixeltable Cloud after pxt db update. This post follows one file through three stages: the file, the first deploy, and every change after it.

The stack the file replaces#

A multimodal feature usually takes four products: an object store for the bytes, a vector database for the embeddings, an orchestrator to run the models, and a FastAPI service to put a URL on the result. Keeping them in agreement is a second job. The orchestrator re-runs rows that did not change. Nobody deletes the embedding when its source file goes. A handler copies a column into JSON by hand.

Pixeltable keeps all four in the table. The longer argument is The Unified Multimodal Backend Agents Build With. This post is the path.

Six-panel comic. The old AI stack: a character tangled in cables between an object store, a vector database, an orchestrator, and FastAPI glue. Collapse it into one file: one machine labeled app.py for database, orchestration, and serving. Multimodal TableModel: a cabinet holding pxt.Image, pxt.Video, pxt.Audio, pxt.Document, __indexes__, and a uuid7() primary key. Computed columns: raw inputs go in, frames, chunks, and embeddings come out. Declarative HTTP routes: FastAPIRouter ingest with POST /docs, /docs/update, and /titles. Built for coding agents: an agent writes app.py and the reviewer sees one diff.
The stack, the file that replaces it, and the four things the file declares.

Stage 1: one file#

bash

Python 3.11 or later. pxt init marks the project root and writes pixeltable.toml. pxt service example writes this file, shown here without its docstring and comments:

python

Three kinds of line do the work.

  • An annotation, title: pxt.String, is a column you insert.
  • An assignment, summary = excerpt(title), is a computed column. It runs on every insert and update. excerpt is a @pxt.udf in the same file, and no loop calls it. The id column is a uuid7() generated on insert.
  • A route is HTTP over those columns. POST /docs inserts a row and returns its id and computed columns. POST /docs/update takes that id and a new title. POST /titles computes without storing a row.

The example uses strings so the first response is easy to read. The same class takes pxt.Image, pxt.Video, pxt.Audio, and pxt.Document columns. An iterator turns one row into many, a document into chunks or a video into frames, and an embedding index is a list on the class. This is the retrieval file from the multimodal backend docs:

python

Inserting a PDF adds its chunks, their embeddings, and the index entries. There is no vector database to keep in sync and no chunking framework to call.

The file is the unit an agent edits#

The whole backend is one file, so a coding agent holds all of it in context and you review one diff. The Pixeltable skill teaches the agent to write a TableModel and computed columns rather than per-row model loops and a separate vector database:

bash

pxt skills install copies the same skill into the repository you start the agent in.

Two switches: tables, then HTTP#

bash

my_app is the catalog directory the tables go in. pxt schema update creates and migrates the tables. It starts no HTTP. pxt service update starts the routes. It creates no tables. -f skips the confirmation prompt. pxt service list prints each route with its inputs and outputs:

text

The port is assigned, so read it back rather than hardcoding it:

bash

The insert computed both columns before it answered. Calling a model works the same way: the column is an assignment to a provider function, and the route returns its output.

Stage 2: the same file on Pixeltable Cloud#

Pixeltable Cloud is in Limited Beta. With no account, pxt new creates a trial organization and a database named main, and prints the pxt:// URI, the pixeltable.toml entry, and the commands below with your names filled in. Claim the trial at the URL it prints, or it is deleted, normally 48 hours later. The pxt commands need no API key. Calling a service over HTTP does, and a trial gets one only after the claim (see below).

With an account, sign in and list your organizations. Create one only when pxt org list prints No orgs.: a person can own one free organization, and pxt org create provisions its main database.

bash

Add a hosted entry to pixeltable.toml, beside the unnamed local entry pxt init wrote. Replace org with your organization name:

toml

A new database accepts pxt db update only after pxt db status pxt://org:main shows AVAILABLE. Then run three commands, in this order, from the project directory, and a fourth that prints the URL. pxt db update and pxt service update ask for confirmation. With no terminal to answer, as in an agent or CI, they refuse and exit 3 unless you pass -f. pxt schema update asks only before a destructive change.

bash
  1. pxt db update uploads the project and builds the image. The first one takes several minutes and returns when the database is ready. It inserts no rows and starts no routes.
  2. pxt schema update creates the hosted tables.
  3. pxt service update starts the routes. pxt service list prints the URL, which looks like https://{org}-{db}.svc.pxt.run/<service>. Copy it from the command.

The local and hosted tables now come from the same file. A Cloud table path is the URI plus the table name:

python

Media goes to the home bucket#

Every Cloud database has a private home bucket at pxt://org:main/buckets/home, and hosted tables write media there with no destination= and no bucket setup. Inserting a local file path on a Cloud table uploads the file. A service route returns a media column as a signed URL that lasts an hour. An app backend signs at most 100 files per call with POST https://storage.pixeltable.com/org/main/sign, for 1 second to 7 days, 3,600 seconds when expires_in is omitted.

Two credentials, kept apart#

Provider keys, such as OPENAI_API_KEY, are secrets that the database and its services read at startup. The key your backend sends in X-api-key is a Pixeltable API key. Keep it on your server. The browser calls your server.

bash

A key created without --grant acts as you. A trial's services answer only the trial's own key, which pxt new never prints: claim the trial, then run pxt key create.

Organization and database scopes, sizing, and keys limited to one service are in Configure Pixeltable Cloud.

Stage 3: day 2, three layers#

A hosted database runs three things from your project, and each one moves on its own.

LayerWhat it holdsA change costs
ImageDependencies from uv.lock or requirements.txt, the Python version, system packagesA rebuild, the slow step
Project filesapp.py, its UDFs and routes, and whatever else the entry selectsAn upload, no rebuild
SettingsThe hosted entry's vars and db_* settings, and sections such as [openai]A restart, no upload or rebuild

All three go through pxt db update, which works out which one changed. Editing a UDF costs an upload, not a container build. Without uv.lock or requirements.txt, the image has Pixeltable only. That is enough for the generated file. List anything else app.py imports in one of them. In an agent or CI, pass -f to each pxt db update and pxt service update below.

You changedRun
A UDF body or a routepxt db update, then pxt service update
A column or a tablepxt db update, then pxt schema update, then pxt service update
A dependency, the Python version, a system packagepxt db update, then pxt service update. The image rebuilds. Until pxt service update, running services keep the old image, or, when the rebuild raises Pixeltable's metadata version, stay at zero pods.
A setting in pixeltable.tomlpxt db update, then pxt service update
cpu, memory_mb, disk_gb, or workers on the entrypxt db update. One resize: the pods restart once.
A secretpxt secret set, then pxt db restart and pxt service restart
Nothing, but the last update failedpxt db retry retries it. pxt db build-image forces a rebuild.

Diff before you ship#

bash

Each prints what its update would change and applies nothing. Exit 0 means nothing is pending. Exit 2 means a change is. Add a column to Docs and pxt schema diff app.py my_app names it before anything runs:

text

A script or an agent can gate the deploy on that exit code.

Operate and sleep#

bash

pxt db stop stops the pods and keeps the data. pxt db start wakes them.

Deploy from a cloud coding agent#

A cloud agent's sandbox usually limits outbound traffic. Allow these hosts, all on port 443:

HostUsed by
internal-api.pixeltable.compxt login, pxt db, pxt secret, pxt key, pxt org, pxt service
api.workos.compxt login and renewing its session
www.pixeltable.com, signin.pixeltable.compxt new
codeload.github.compxt skills install
*.s3.amazonaws.compxt db update, to upload the project
*.r2.cloudflarestorage.comMedia in the home bucket
*.svc.pxt.runRequests to a hosted service
*.pxt.runEverything that uses tables: pxt schema update, pxt service update, pxt.get_table()

The *.pxt.run connection is TLS on TCP port 443. From Pixeltable 0.7.19, pxt opens it with an HTTP CONNECT through the http:// proxy that HTTPS_PROXY names, unless NO_PROXY lists the host, and connects directly when there is no such proxy. Claude Code on the web sets HTTPS_PROXY and answers a direct connection itself, so there only the CONNECT reaches your database: use 0.7.19 or later, and leave *.pxt.run out of NO_PROXY. Codex cloud has not been tested. The settings for each agent are under Network access.

Local and Cloud, side by side#

StepLocalPixeltable Cloud
Start the projectpxt init, pxt service example --out app.pyThe same, plus name = 'pxt://org:main', or pxt new
Ship the filesRuns from local diskpxt db update pxt://org:main
Tablespxt schema update app.py my_apppxt schema update app.py pxt://org:main
HTTPpxt service update app.py my_apppxt service update app.py pxt://org:main
Previewpxt schema diff app.py my_apppxt db diff pxt://org:main, pxt schema diff app.py pxt://org:main
MediaLocal diskpxt://org:main/buckets/home, signed URLs
Poster: the entire AI backend in one app.py file. A machine labeled app.py holds a multimodal database of tables, an orchestration conveyor, and a server for HTTP routes, and outputs embeddings and predictions.
To serve HTTP routes, install pixeltable[serve].

Email [email protected] for a Cloud account, or run pxt new. The reference is Deploy to Pixeltable Cloud. Calling a hosted route from TypeScript is How to serve a typed AI endpoint.

Frequently asked questions

Declarative. Multimodal. Incremental.

Focus on innovation, not infrastructure.

10-minute tutorial · Join community