Deploying a Python App
Deploy a Flask, Django, or FastAPI app, or a plain Python script, and get it running with HTTPS and live logs. You don’t write a Dockerfile, pick a Python version, or type a start command: they’re worked out from your project on every deploy.
Note: backends, Python included, require the Pro plan.
Deploy in one command
From your project folder:
pbc deploy --name my-api
When the status turns running, your app is live at
https://my-api.pocketbasecloud.com. Redeploy later with pbc deploy.
Prefer the portal? Open your project’s Backends tab, click New Backend, and drop in your project folder. The detected runtime, Python version, and start command are shown before you click Create.
Upload your code and your dependency file. Leave out your virtualenv
(.venv, venv): it is skipped automatically, and dependencies are installed
fresh inside the container.
What you can deploy
| You have | It runs as |
|---|---|
| A Flask app | your app, served by gunicorn (or waitress) if you list it, else flask run |
| A Django project | gunicorn on your wsgi.py if you list it, else Django’s own server |
| A FastAPI, Starlette, Litestar, or Quart app | uvicorn (or the ASGI server you list) |
| Streamlit, Gradio, Dash, Sanic, Bottle, or Falcon | the framework’s own way of starting |
| A Celery worker | celery -A <module> worker |
| A script: bot, worker, scraper | python main.py (or app.py, server.py, or your only script) |
Apps with an app factory (create_app()) or a package layout (app/main.py)
are recognised too.
If your app answers web requests, it needs to listen on the port in PORT.
The generated start commands already do. If you start the server yourself:
import os
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 8000)))
A script that serves no web page doesn’t need a port. It just has to keep running. See Run a Python script on a schedule.
Your dependencies are installed for you
Keep whichever tool you already use. The file in your project decides:
| Your project has | Installed with |
|---|---|
uv.lock |
uv |
poetry.lock |
Poetry (main dependencies only, not dev) |
Pipfile |
pipenv |
requirements.txt |
pip |
only pyproject.toml |
the dependencies it lists |
Dev-only dependencies are not installed. If your start command needs a server you forgot to list, such as uvicorn, it is installed for you.
Pick the Python version
Python 3.10, 3.11, 3.12, 3.13, and 3.14 are supported. Without a pin you get 3.12. To choose, add any one of these, checked in this order:
.python-version, for example3.13runtime.txt, for examplepython-3.11.9requires-pythoninpyproject.toml(or Poetry’spython = "^3.11")python_versionin yourPipfile
The version is read again on every deploy, so changing the file is enough. To
force a version for one deploy, add --python-version 3.13.
Python 2 and versions older than 3.10 are not supported. A project pinned to one fails to deploy and names the file to change. Nothing is silently swapped in.
Use your own start command
Most apps need nothing here. To choose it yourself, add a Procfile with a
web: line. It wins over detection:
web: gunicorn myproject.wsgi --bind 0.0.0.0:$PORT --workers 2
You can also set the start command on the backend’s Settings page, or pass
--start to pbc deploy.
Keep your app within its memory
Each backend has 1 GB of memory. A typical Flask, Django, or FastAPI app uses 60–100 MB per worker, so one or two workers fit comfortably.
The thing to avoid is sizing workers from the machine’s CPU count, such as
workers = multiprocessing.cpu_count() * 2 + 1 in gunicorn.conf.py, or
--workers $(nproc). Your backend shares a larger machine, so that formula
starts far more workers than it needs, and the backend runs out of memory and
restarts. Set a fixed number instead:
gunicorn app:app --workers 2 --bind 0.0.0.0:$PORT
Loading a large machine-learning model (PyTorch and similar) can need more than 1 GB on its own. That kind of app is not a good fit for a backend today.
Environment variables
Read your secrets from the environment as usual:
import os
stripe_key = os.environ["STRIPE_SECRET_KEY"]
A .env next to your code is pushed on every pbc deploy. See
Backend Environment Variables.
When something goes wrong
Open the backend’s Logs page, or run:
pbc logs backend --name my-api -f
Output shows up immediately; you don’t need to flush print().
| You see | Fix |
|---|---|
ModuleNotFoundError |
add the package to your dependency file and redeploy |
| the app starts but the URL doesn’t answer | listen on 0.0.0.0 and the PORT variable, not localhost:5000 |
| the backend keeps restarting with no error | too many workers, see memory |
| “Python 2 is not supported” | pin 3.10 or newer, see Pick the Python version |