Summary: A Pixeltable Cloud database is one entry in pixeltable.toml. The entry names the database, chooses which project files it receives, and optionally sets the Python environment and the size it runs at. Deploy with pxt db update, then pxt schema update, then pxt service update. Provider keys are secrets. The key your app sends is a separate Pixeltable API key. This is the configuration reference for that path. The reference docs are Deploy to Pixeltable Cloud.
Pixeltable Cloud is in Limited Beta. Email [email protected] for an account, or start with pxt new, which creates a trial organization and database main. Claim it within 48 hours. The same app.py you run locally is the file you deploy. If you are declaring that file for the first time, start with How to serve a typed AI endpoint.
Two runtimes, one project#
A hosted database does two jobs, and they are not the same process.
| Runtime | What it does | How you start it |
|---|---|---|
| Database | Holds the catalog. Runs pxt.get_table, view iterators, and index builds. You run pxt schema update against it. | pxt db update |
| Service | Serves the HTTP routes FastAPIRouter declares in app.py. | pxt service update |
Interactive HTTP does not run inside the catalog process. A code upload updates the project both of them read. An image rebuild updates the Python environment both of them run. Size the database on its [[pixeltable.database]] entry. pxt service update starts the service on the platform default.
The pixeltable.toml entry#
pxt init marks the project root. Keep the local database entry it writes, and add a hosted one. Replace myorg with the slug from pxt org list. pxt org create already provisions main.
If the project already has a pyproject.toml, pxt init writes there instead. Use [[tool.pixeltable.database]] for the hosted entry. pixeltable.toml wins when both files exist.
A URI with no matching entry is an error. pxt db update pxt://myorg:main looks up the entry whose name is that URI. Leave cpu, memory_mb, disk_gb, and workers out until you have a reason to change the default.
When the default environment or size is not enough, the same entry is where those settings go:
- The default packages every file git would not ignore, including
app.pyat the project root.excludedrops globs from that set.includeadds files an exclude or.gitignorewould have dropped. It does not replace the set, soinclude = ["app/**"]does not mean "only the app directory," and it does not drop a rootapp.py.include_onlyis the whitelist. It cannot be combined withincludeorexclude. Leaveincludeunset for theapp.pythis post deploys. system_dependenciesare conda-forge package specs, installed with micromamba when the image is built.ffmpegis the usual one. An apt package name is not a spec.python_versionis3.12or3.12.8.uv_optionsis an optional extra argument string foruv sync.cpu,memory_mb, anddisk_gbare the database pod. Memory has to stay between 1,024 and 4,096 MB per vCPU. A size outside that range is refused.- Leave
workersunset. The catalog database runs as one worker. Give it more CPU and memory when schema updates, iterators, or index builds need it. Do not raise the worker count to get more HTTP throughput. That is the service. disk_gbis local disk for the file cache. Rows and media are not stored on it.
pxt db diff pxt://myorg:main prints what update would change and applies nothing. Exit 0 means the database already matches the entry. Exit 2 means a change is pending. Field reference: cloud configuration.
Image rebuild or project upload#
pxt db update decides which of two artifacts changed.
| What changed | What update does |
|---|---|
app.py, a UDF, a route, any other selected source file | Uploads the project archive. Does not rebuild the image. |
A dependency, python_version, or a system package | Rebuilds the image. This is the slow step. |
cpu, memory_mb, disk_gb, or workers | Resizes. The pods restart once. |
The image installs packages from uv.lock or requirements.txt. With neither, pxt db update warns and the image contains Pixeltable only, which is enough for the generated example app. Anything else app.py imports belongs in one of those files. The first pxt db update builds the image and returns when the database is ready. That takes several minutes. Later code-only updates do not.
If a command reports an unsupported proxy protocol version, this Pixeltable and the database image disagree. When your local install is newer, upgrade the lockfile pin and run pxt db build-image pxt://myorg:main. pxt db restart keeps the image the pods already run. When the database is newer, run pip install -U 'pixeltable[serve]'.
Deploy order#
A new database accepts pxt db update only after pxt db status pxt://myorg:main shows AVAILABLE. From the project directory, in order, and with -f when there is no terminal to confirm in:
pxt db updateuploads the project and applies the entry. It does not insert rows and it does not start routes.pxt schema updatecreates and migrates the tables. It does not start HTTP. Running it before the project is on the database fails with404: UDF not found.pxt service updatestarts the hosted routes.pxt service runis local only.
pxt service list prints the URL and its routes. The host looks like https://{org}-{db}.svc.pxt.run/<service>. Copy it from the command. Do not hardcode it, and do not send service traffic to the control-plane host. Calling that service from TypeScript is How to serve a typed AI endpoint.
What to run after a change#
| You changed | Run |
|---|---|
A UDF body, a route, or any .py the entry selects | pxt db update, then pxt service update so running services pick up the upload |
A column or a table in app.py | pxt db update, then pxt schema update, then pxt service update |
| A dependency, the Python version, or a system package | pxt db update. The image rebuilds. |
cpu, memory_mb, disk_gb, or workers | pxt db update. One resize. |
| A secret | pxt secret set, then pxt db restart and pxt service restart |
| Nothing, but the last build failed | pxt db build-image pxt://myorg:main |
Where media goes#
Every Cloud database has a home bucket at pxtfs://myorg:main/home. Hosted tables and services write there with no destination= and no destination environment variables. Inserting a local file path on a Cloud table uploads the file.
Set a destination only in two cases.
- Local Pixeltable writing into that same bucket: sign in with
pxt loginorPIXELTABLE_API_KEY, then setPIXELTABLE_INPUT_MEDIA_DESTandPIXELTABLE_OUTPUT_MEDIA_DEST. See Cloud storage. - Your own bucket: store
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY(or the GCS or Azure names) withpxt secret, and point a column ats3://,gs://, orwasbs://.
db_input_media_dest and db_output_media_dest on the database entry change the default for inserted or computed media. The home bucket remains the default when you set neither.
Secrets: organization, then database#
PIXELTABLE_API_KEY is how the CLI and your backend authenticate to Pixeltable Cloud. OPENAI_API_KEY and the other provider keys are secrets. They are not the same value, and provider keys do not belong in app.py.
An organization secret applies to every database. A database secret applies to that database and overrides the organization value when the names collide.
A process reads its secrets once, at startup. pxt secret list prints names, never values. You can set the same keys in the Cloud dashboard.
API keys for the service#
The CLI and pxt.get_table('pxt://myorg:main/docs') work with a pxt login session. A backend that calls the hosted HTTP service needs a key. Keep it on the server. The browser calls your server.
SERVICE_URL is the endpoint pxt service list printed. The example app's insert route is /docs on that URL. A key created without --grant acts as you. Cloud checks X-api-key first. A request that also sends Authorization: Bearer is authenticated as that API key.
A key with --grant is a runtime key. It belongs to the organization and reaches only its grants. Grants are a preview: Cloud refuses them until they are enabled for the organization. Until then, omit --grant.
| Grant | What that key can do |
|---|---|
access:pxt://myorg:main/services/ingest | Call the ingest service |
access:pxt://myorg:main/services | Call any service in main |
access:pxt://myorg:main | That database's services and its storage |
manage:pxt://myorg:main/services | Create, start, stop, and delete services. It cannot read what those services return. |
access and manage do not imply each other. The secret prints once. pxt key update changes grants without reissuing it. The full table is under pxt key. For a typed TypeScript client, use the walkthrough in serve a typed AI endpoint.
Operate it#
stop releases compute and keeps the data. pxt db delete deletes a database and its storage. It refuses the organization's current default database. Set a different default first. A new organization's default is main.
Local and Cloud, same file#
| Local | Cloud | |
|---|---|---|
| Project | pxt init | the same project, plus name = 'pxt://myorg:main' |
| Tables | pxt schema update app.py my_app | pxt schema update app.py pxt://myorg:main |
| HTTP | pxt service update app.py my_app | pxt service update app.py pxt://myorg:main |
| Media | local disk | pxtfs://myorg:main/home |
Install with pip install -U 'pixeltable[serve]'. Sign in with pxt login for an account you already have. The commands above are the configuration. The application is still one app.py. Declaring the routes and calling them from Next.js is How to serve a typed AI endpoint.


