Skip to content

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:

  1. .python-version, for example 3.13
  2. runtime.txt, for example python-3.11.9
  3. requires-python in pyproject.toml (or Poetry’s python = "^3.11")
  4. python_version in your Pipfile

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

Next steps