Guides
Python — Django, FastAPI and Flask
Running a Django, FastAPI or Flask app on Meghly — the commands that run, Celery workers, migrations and static files.
What runs
- Python 3.14, 3.13 and 3.12.
- Dependencies:
requirements.txt,pyproject.toml(uv or Poetry) or aPipfile— installed with the tool they belong to. - The version comes from
.python-version, otherwise fromrequires-pythoninpyproject.toml.
3.13What Meghly runs
| Framework | Web process | Also |
|---|---|---|
| Django | gunicorn <project>.wsgi --workers 2 | collectstatic in the build, migrate in the release |
| Django + Channels | uvicorn <project>.asgi:application | WebSockets work |
| FastAPI | uvicorn <module> --proxy-headers | — |
| Flask | gunicorn <module> --workers 2 | — |
Everywhere the port is 8080 and the address 0.0.0.0 — Meghly sets them. The server must be in your dependencies, though: gunicorn for Django and Flask, uvicorn for FastAPI.
django>=5.2
gunicorn
psycopg[binary]
whitenoiseIf it is none of these, set your own start command in the app's Processes — just make sure the app listens on PORT.
Django
Settings
The app runs behind an HTTPS router, so keep these in settings.py:
import os
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG") == "1"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
CSRF_TRUSTED_ORIGINS = [f"https://{h}" for h in ALLOWED_HOSTS if h]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")Then set DJANGO_SECRET_KEY (as a secret) and DJANGO_ALLOWED_HOSTS in Environment — the app's address and your domains, separated by commas.
Database
A linked database brings DATABASE_URL. dj-database-url reads it easily:
import dj_database_url
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}python manage.py migrate --noinput runs by itself before every deploy, with the migration login.
Static and media files
- Static (CSS, JS):
collectstaticruns in the build. Serve the files with WhiteNoise —whitenoise.middleware.WhiteNoiseMiddlewareright afterSecurityMiddlewareinMIDDLEWARE. - Media (uploads): set
MEDIA_ROOT = "/app/media". Meghly keeps this folder across deploys.
Celery
With celery in the dependencies, Meghly adds a worker process: celery -A <project> worker (in FastAPI or Flask too — there with the module holding the Celery() object). With django-celery-beat, a separate beat process comes too. Link Redis or RabbitMQ to the app as the broker, then:
CELERY_BROKER_URL = os.environ.get("REDIS_URL") or os.environ.get("RABBITMQ_URL")FastAPI
Meghly finds the FastAPI() object and builds a command such as uvicorn main:app. If it cannot find it, Detect says so — then set the command in Processes:
uvicorn app.main:app --host 0.0.0.0 --port 8080 --proxy-headersWith Alembic, alembic upgrade head runs by itself before every deploy.
Flask
Flask runs on gunicorn. Meghly finds the Flask() object; failing that it assumes app:app (the app in app.py). For an app factory or another name, change the command in Processes, such as gunicorn "myapp:create_app()" --bind 0.0.0.0:8080.
When something goes wrong
| What you see | Cause and fix |
|---|---|
| Detect: "Add gunicorn to your requirements" | Add gunicorn to requirements.txt (uvicorn for FastAPI). |
DisallowedHost | Put the address and domains in DJANGO_ALLOWED_HOSTS. |
CSRF verification failed on forms | CSRF_TRUSTED_ORIGINS and SECURE_PROXY_SSL_HEADER (see above). |
| No CSS | Add WhiteNoise. |
| Uploads disappear after a deploy | MEDIA_ROOT = "/app/media". |