Overview
Pixeltable can expose table operations and queries as HTTP endpoints viapixeltable.serving.FastAPIRouter. You can configure endpoints either
programmatically in Python or declaratively with a TOML service file.
This page builds on the HTTP-based paths from the
Deployment Strategies
overview:
- Approach 2: Pixeltable as Full Backend:
use the Pixeltable SDK’s
FastAPIRouterwhen you already have, or are building, a FastAPI app. - Approach 3: Declarative Serving:
use the Pixeltable CLI command
pxt servewhen you want Pixeltable to create and run the FastAPI app from TOML or CLI flags.
pxt serve or the Python serving API:
Quickstart (TOML)
This is the primary config-file path for Approach 3: Declarative Serving. Add a[tool.pixeltable] section to your pyproject.toml:
You can also use a standalone TOML file (
pxt serve my-service --config service.toml) with the same route syntax but [[service]] and [[service.routes]] as top-level keys. The pyproject.toml format is preferred for new projects.http://localhost:8000 with auto-generated
OpenAPI docs at /docs.
Quickstart (Python)
This is the SDK path for Approach 2: Pixeltable as Full Backend.Compute without persisting
Table.compute() materializes computed columns for
input rows and returns the results without writing to the table. Use it for previews,
dry-runs, or request/response APIs that should not store every call.
add_compute_route (or @router.compute_route):
add_insert_route, except no row is inserted. For declarative
TOML/pxt serve configs, type = "compute" is currently treated as an insert alias;
use the Python FastAPIRouter API when you need true non-persisting compute.
Quickstart (single-endpoint CLI)
This is a single-endpoint CLI path for Approach 3: Declarative Serving. For quick experiments and one-off endpoints, you can skip the TOML file and configure a single route directly on the command line:[[service.routes]]
TOML entry. It is meant for development and ad-hoc serving; for anything
beyond that use the TOML file (it is the only way to expose more than one
endpoint).
Decorator-style routes
add_insert_route() / add_compute_route() / add_update_route() build a response
model automatically from the column schema. When you need a different response
shape — e.g. a richer API envelope, derived fields, or a stripped-down payload —
use the @router.insert_route / @router.compute_route / @router.update_route
decorators. The decorated function receives the requested output columns as keyword
arguments and returns a pydantic.BaseModel subclass that defines the HTTP response body.
- Every parameter must be keyword-only and have a type annotation.
- Every parameter name must appear in
outputs, and everyoutputsentry must be a parameter. - Parameter annotations must match the column types (strict nullability: a
nullable column requires
T | None). Media columns are delivered as URL strings, so annotate them asstr. - The return annotation must be a
pydantic.BaseModelsubclass.
background=True flag as the non-decorator
forms; when enabled, the decorated function’s return value is delivered as the
background-job result.
The decorator forms are Python-only — there is no equivalent in the TOML
service file.
Exporting rows to an external database
Insert and update routes can export each successful request as a row in an external SQL database. Configure it via the Python API, the TOML service file, or the CLI; all three forms route through the sameSqlExport specification.
Each request performs the Pixeltable insert/update first; only if it succeeds
does the row get written to the external table.
Python API. Pass an export_sql=SqlExport(...) argument to
add_insert_route, add_update_route, or the decorator forms.
[routes.export_sql] table under any insert or update
route. The same fields apply.
--export-sql-*
flags on pxt serve insert and pxt serve update.
outputs, with media-typed columns rendered as URL strings (so the
corresponding target columns must be string-typed). Schema compatibility is
validated once at registration; the target table must already exist or
registration fails. The engine and connection pool are cached per
db_connect, so multiple routes pointing at the same database share one pool.
SqlExport.method controls how each row is written:
'insert'(default): append the row viaINSERT ... VALUES. The target acts as an audit log — replaying the same request produces a duplicate.'update': update the row by primary-key match. The target is treated as a current-state view keyed on its primary key. The response columns must include all primary-key columns of the target plus at least one non-PK column to set; the target table itself must declare a primary key. This is a strict update, not an upsert — if no row matches, the request fails with HTTP 500.'merge'(upsert): not yet supported.
add_insert_route and method='update', a Pixeltable insert
triggers a target-side update. This is intentional: it supports the pattern
where the Pixeltable table is append-only (e.g. an event log) but the target
is a deduplicated, current-state view.
If the external write fails after the Pixeltable insert/update has already
committed, the request returns HTTP 500; no rollback is performed.
export_sql= is mutually exclusive with return_fileresponse=True and is
compatible with background=True (the SQL write runs in the worker thread).
See SqlExport
for the full target specification.
TOML Service File Reference
[service] (optional)
Top-level settings for the FastAPI application and server.
modules (optional)
A list of additional Python modules to import at startup, for their
registration side effects. The module that hosts a query route’s dotted
path is imported automatically, so this is only needed when you depend
on @pxt.query / @pxt.udf definitions in other modules that wouldn’t
otherwise be loaded.
[[service.routes]]
Each [[service.routes]] entry defines one HTTP endpoint. The type field determines
the route kind and which additional fields are valid.
Common fields
When
background = true, the endpoint returns immediately with:
job_url until status is "done" or "error".
Insert routes
Insert a single row into a table and return the resulting column values.
File uploads: when
uploadfile_inputs is set, the request uses multipart/form-data
instead of JSON. All other inputs become form fields.
Update routes
Update a single row identified by its primary key values, and return the updated columns (including any computed columns that depend on them).
The request body carries the primary key values (to identify the row) plus the
values to update, as JSON fields:
Media-typed columns (image, video, audio, document) cannot currently be
updated. To replace a media value, delete the row and insert a new one.
Delete routes use HTTP POST, not the HTTP DELETE method. Update client-side fetch calls accordingly.
Delete routes
Delete rows matching the given column values and return the count of rows affected.Media columns (
pxt.Image, pxt.Video, pxt.Audio, pxt.Document) serialize as URL strings (e.g., /media/path/to/file.pdf). The client receives a string, not binary data.Query routes
Execute a@pxt.query or retrieval_udf function and return the results.
The
query field is a dotted Python path (e.g., "myapp.queries.search_docs");
the module portion is imported automatically when the route is resolved.
Multi-row response (default):
one_row = true):
Full example
Reading Back Computed Columns After Insert
Usereturn_rows=True to get all column values (including computed columns)
directly from insert(), update(), or batch_update() without a follow-up
query.
status.rows is a list of plain dicts. For typed access, use Pydantic’s
model_validate() with extra="ignore" (row dicts contain every column;
ignore the ones you don’t need):
return_rows=True— any time you insert a row with computed columns and need the results backto_pydantic()— when reading from aResultSet(after.collect())model_validate()— when reading fromstatus.rows(plain dicts fromreturn_rows=True)
Background jobs
Any route can setbackground = true. The endpoint returns immediately with a
job handle:
background is mutually exclusive with return_fileresponse.
CLI Reference
For the fullpxt command-line reference (all subcommands, flags, and usage patterns), see the dedicated CLI Reference page.
Quick examples: