Skip to content
homeport

Python

Django, FastAPI and Flask, deployed from the repo

Push a Python app and homeport recognises it from uv.lock or requirements.txt. Your app ships with its own Python, so there is no Dockerfile to write and no virtualenv to set up.

Frameworks

What homeport reads

pyproject.toml + uv.lock
Installs exactly what the lockfile says, without dev dependencies. A uv.lock your pyproject.toml has moved past fails the build, saying to run uv lock.
requirements.txt
Installed with uv, as pinned as the file is.
.python-version, runtime.txt or requires-python
The Python to build and run with, unless you pick one in the build settings: 3.12, 3.13, 3.14 or 3.15. With none named, 3.14.
package.json
When it has a build script, your front end (Tailwind, say) is built with Bun first, so Django’s collectstatic collects it. node_modules never ships.

What you get

  • Your app and its own Python in one bundle: no Dockerfile, no virtualenv
  • Compiled to bytecode in the build, so a wake doesn’t compile every import again
  • gunicorn or uvicorn added for you when your dependencies don’t list one
  • gunicorn runs 2 workers of 4 threads; WEB_CONCURRENCY and GUNICORN_CMD_ARGS override it
  • Static files served: Django’s through WhiteNoise, FastAPI’s StaticFiles and Flask’s static/ as they are
  • Postgres in one click, with DATABASE_URL set for you and migrations run as the release command
  • Asleep when idle and woken by the next request, as a Node app is
  • HTTPS on a homeport.run address, and your own domain on paid plans
  • Environment variables set in the dashboard, exportable as .env

When you need more

The start command, release command and processes are set in the dashboard under Settings → Build settings, or in an optional homeport.yaml. Each is arguments to your app’s Python, without a shell, so a Celery worker is -m celery, not celery:

run: -m gunicorn --bind 0.0.0.0:$PORT mysite.wsgi
release: manage.py migrate --noinput
processes:
  worker: -m celery -A mysite worker