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
Django
Recognised by manage.py and django in your dependencies. Served by gunicorn from your project’s wsgi, collectstatic run in the build, and manage.py migrate as the release command.
FastAPI
Recognised by app = FastAPI( in main.py, app.py, app/main.py and the like. Served by uvicorn, with alembic upgrade head as the release command when you have an alembic.ini.
Flask
Recognised by app = Flask( in the same files, or wsgi.py. Served by gunicorn, with the same Alembic release command for Flask-Migrate.
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