User guideBuilding
Python
Flask, FastAPI, Streamlit, marimo and plain Python — how each is detected and started.
| Framework | Detected by | Started with |
|---|---|---|
| Streamlit | streamlit in your dependencies |
streamlit run, mounted under your app’s path |
| FastAPI | fastapi in your dependencies |
uvicorn with --root-path set |
| Flask | flask in your dependencies |
gunicorn if your dependencies include it, otherwise flask run — see Flask |
| marimo | a root .py that imports marimo and builds a marimo.App |
marimo run, mounted under your app’s path |
| Python | anything else | python <entry point> |
Dependencies are read from requirements.txt, else pyproject.toml, else
Pipfile. marimo as a dependency alone is not the trigger — a Flask app that
imports it stays Flask.
Toft never adds a web server you didn’t ask for. If your dependencies include
gunicorn, your Flask app is served by gunicorn; otherwise it runs on Flask’s
development server. The build log says which one your app got:
Serving with gunicorn (app), from this app's requirements.To move to gunicorn, add gunicorn to requirements.txt and deploy again.
gunicorn needs to know which object is your app. Toft looks in your entry point
for a top-level app = Flask(...) (or an object named app or application),
then for a create_app() or make_app() factory that takes no arguments. If it
finds none, the app runs on Flask’s development server even with gunicorn
installed, and the build log says so.
Toft sets the address gunicorn listens on. To choose workers, timeouts and
other options, set GUNICORN_CMD_ARGS as an
environment variable, for example
--workers 4 --timeout 60.
Entry point
Section titled “Entry point”Every Python app except marimo needs one of these at the root, picked in this
order: app.py, main.py, streamlit_app.py, server.py, wsgi.py. With
none, the deploy is refused.
The contract
Section titled “The contract”Listen on PORT, bound to HOST. Toft passes both to Streamlit, FastAPI,
Flask and marimo for you; a plain Python app reads them from the environment.
Anything you send to the browser must respect the /apps/<slug> prefix. See
Base paths.
Dependencies
Section titled “Dependencies”Toft creates a virtual environment with uv and
installs requirements.txt (uv pip install -r), or, if there’s none, your
pyproject.toml project (uv pip install .). A Pipfile is used for
detection only. The Toft SDK is installed for you.
Pin your versions. An unpinned requirements.txt resolves differently over
time.
Version
Section titled “Version”[runtime]python = ">=3.12,<3.14"See Language versions.
With no pin, requires-python in pyproject.toml is used only when it rules out
the install’s default Python. Then Toft builds with the newest version it allows. See
Python’s requires-python.
Work that finishes
Section titled “Work that finishes”A web app must keep running — a script that computes something and exits looks like a crash. Run batch work as a job, and have the web app show the result.