← Blog
Engineering

Python app hosting in 2026: Django, Flask and FastAPI

Yura Oak
Yura OakAugust 21, 2026

Python app hosting comes down to one question: is your app only a web process? If it is, Google Cloud Run and Render's Starter tier are cheap and boring in the best way. If it also has a Celery worker, a scheduler, a WebSocket endpoint, or a migration step, you want a platform that runs processes rather than request handlers — Lizard, Railway, Fly.io, or DigitalOcean App Platform. PythonAnywhere is still the fastest way to put a teaching project online, and it no longer costs $5.

Written 20 August 2026. Prices read off each provider's own page that week.


The short answer, by workload

Your appHost it on
A Django site with Postgres and a Celery workerLizard, Railway, or Render
A FastAPI service behind a load balancerGoogle Cloud Run, or Lizard if it holds connections open
A Flask app for a class or a demoPythonAnywhere, or Render's free tier
A Streamlit or Gradio demoLizard or Render — both keep a long-lived process
An ML job that runs and exitsCloud Run Jobs, or a Lizard sandbox
Anything that must never cold-startLizard or Railway — both keep the process up (Fly.io autostops by default)

What Python hosting costs in 2026

PlatformEntry priceWhat you getPostgres
PythonAnywhere$10 a month (Developer)One web app, a console, scheduled tasksMySQL included; Postgres as a paid add-on on Custom plans
RenderFree (0.1 CPU, 512 MB), or $7 a month (Starter)Starter is 0.5 CPU, 512 MB; free services spin down after 15 minutesManaged Postgres, from free
RailwayFree at $0 a month, or $5 a month (Hobby)Hobby includes $5 of usage; $0.0278 per vCPU-hour, $0.0139 per GB-hourFirst-party
LizardFree to start, $5 a month (Hobby)Same rates, billed on measured useFirst-party, one command
Fly.ioFrom $31 a month for performance-1x1 dedicated vCPU, 2 GBFly Managed Postgres, or bring your own
DigitalOcean App Platform$5 a monthOne small containerManaged Postgres, separate bill
Google Cloud RunFree tier, then per request$0.000024 per vCPU-second, $0.40 per million requestsNo — Cloud SQL is separate
Heroku$7 a month (Basic dyno)512 MB; $25 for Standard-1XEssential-0 at $5 a month

Two changes worth knowing about. PythonAnywhere retired the $5 Hacker tier in January 2026, folding it and Web Developer into a single $10 Developer plan. And Heroku moved to sustaining engineering on 6 February 2026 — supported and patched, but no new features — which is why it sits at the bottom of this table rather than the top, and why the Heroku alternatives are worth a look. For the wider field, see the best PaaS providers in 2026.

What a Python app actually needs from a host

Most Python deploys fail on the same five things. Check a platform against these before the price.

A start command you control. python app.py is not a production server. Django and Flask want gunicorn, FastAPI wants uvicorn, and the host has to let you say so:

gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT   # Django
gunicorn app:app --bind 0.0.0.0:$PORT                      # Flask
uvicorn main:app --host 0.0.0.0 --port $PORT               # FastAPI

The port from the environment. Every platform injects one. Bind to 0.0.0.0 and read $PORT, or the health check never passes and the deploy hangs in a state that reads like a build failure.

A place for migrations. python manage.py migrate has to run somewhere between the build and the first request. A release command, a pre-deploy hook, or an entrypoint line — but somewhere, and once, not per worker.

Static files. Django's collectstatic needs a writable path at build time and a way to serve the result. WhiteNoise in the app is the least-effort answer, and it works everywhere.

A second process type. Celery, RQ, APScheduler, a Discord bot, a poller. If the platform only knows how to run request handlers, this is the wall you hit, and it usually arrives three weeks after you chose the platform.

Deploying Django

Django is WSGI. Serve it with gunicorn, and give it a worker count that matches the CPU you bought:

gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT --workers 3

The four things to get right:

  • ALLOWED_HOSTS must include the domain the platform gives you, or every request returns 400.
  • DATABASE_URL — use dj-database-url and stop hand-writing the DATABASES dict.
  • collectstatic at build time, WhiteNoise in the middleware, STATIC_ROOT set.
  • migrate once per release, not in the web process's startup.

Celery is a second service with the same image and a different command: celery -A myproject worker -l info. It has no HTTP port, so on a request-only platform it does not belong at all.

If you would rather run Django on a server you own, the full VPS deploy is written up here — gunicorn under systemd, nginx, TLS, and the release routine.

Deploying Flask

Flask is WSGI too, and the deploy is shorter:

gunicorn app:app --bind 0.0.0.0:$PORT --workers 2

app:app means the object called app inside app.py. If you use the application-factory pattern, it is gunicorn "myapp:create_app()". Never ship app.run() — Flask's development server is threaded by default but is explicitly not built to be secure, stable, or efficient, and Flask says so itself the moment it starts.

Deploying FastAPI

FastAPI is ASGI, so gunicorn alone will not serve it. Use uvicorn:

uvicorn main:app --host 0.0.0.0 --port $PORT

For several CPU cores, let uvicorn manage the workers itself:

uvicorn main:app --host 0.0.0.0 --port $PORT --workers 4

The old gunicorn -k uvicorn.workers.UvicornWorker route still runs, but uvicorn.workers is deprecated and warns on every boot; if you need gunicorn as the arbiter, install uvicorn-worker and use -k uvicorn_worker.UvicornWorker.

FastAPI apps often hold connections open — server-sent events, WebSockets, streaming responses from a model. On a request-based host those are billed and capped as one long invocation, which is the strongest argument for a platform that runs a real process.

PythonAnywhere, and when it still makes sense

PythonAnywhere is the shortest path from "I wrote a Flask app" to "it has a URL". Browser editor, browser console, scheduled tasks, no Docker and no build step — and you never have to touch a CLI, though PythonAnywhere does ship one (pa). For a course, a tutorial, or a personal tool, that is exactly right.

It stopped being the cheap option in January 2026, when the $5 Hacker plan was merged into the $10 Developer plan. It has never been the option for a containerised app, a WebSocket endpoint, a worker fleet, or anything you intend to scale — the model is one web app on a shared host, not a platform.

Deploying any Python app on Lizard

npm i -g @lizard-build/cli
cd your-app && lizard up

lizardpack reads the repo and writes a real multi-stage Dockerfile on the build node, so you never install Docker locally. For Python it detects, in this order:

  • The package manager. uv.lock or [tool.uv] gives you uv sync --no-dev; Pipfile.lock gives pipenv; poetry.lock gives poetry install --only=main; requirements.txt gives pip.
  • The version. .python-version, then .tool-versions, then requires-python in pyproject.toml. Failing all three, Python 3.13.
  • The start command. A Procfile web: line wins if you have one — which means a Heroku repo deploys unchanged. Otherwise manage.py implies gunicorn on the Django WSGI app, asgi.py implies uvicorn, and an app.py is read to tell FastAPI from Flask.
  • The environment. PYTHONUNBUFFERED=1 and PYTHONDONTWRITEBYTECODE=1 are set for you, so logs appear immediately instead of sitting in a buffer.

One caveat, stated plainly: the Django default assumes your settings package is called app. If your project is myproject, set the start command yourself rather than letting the guess stand.

The rest of a Python stack comes from the same CLI:

lizard add postgres redis          # provision Managed Postgres and Managed Redis
lizard secrets set DATABASE_URL='${{postgres.DATABASE_URL}}' \
     REDIS_URL='${{redis.REDIS_URL}}' --service api   # wire them in by reference
lizard up --service worker --port 0  # Celery, with no HTTP port
lizard ssh --service api -- python manage.py migrate
lizard logs --service api          # runtime output
lizard logs --build --service api  # build output

Each service runs as a long-lived process in its own Firecracker micro-VM: no execution ceiling, a read-write filesystem, and a *.onlizard.com domain with TLS on the first deploy. Lizard bills only for active resources, by the second, on measured CPU, memory and disk rather than the size you picked.


Deploy a Python app in one command

Free to start with $5 of credit and no card. Hobby is $5 a month.

Get started free → lizard.build/login


FAQ

Where should I host a Python app in 2026? For a Django or Flask app with a database and a background worker, use a platform that runs long-lived processes — Lizard, Railway, or Render. For a stateless HTTP API that should cost nothing when idle, Google Cloud Run. For a teaching project or a demo, PythonAnywhere or Render's free tier. Heroku still works but has been in sustaining engineering since February 2026, so it will not gain features.

How much does Python hosting cost? Between free and $10 a month for anything small. Render's free web service costs nothing and spins down after 15 minutes; Render Starter is $7 a month; DigitalOcean App Platform starts at $5; PythonAnywhere Developer is $10; Lizard and Railway start at $5 a month and bill by the second beyond the included credit. A real production Django app with a worker and Postgres lands between $15 and $50 on most of them.

What start command should I use for Django? gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT, with --workers set to roughly two per CPU core. Bind to 0.0.0.0 and read the port from the environment, or the platform's health check never passes. Run python manage.py migrate as a separate release step, not inside the web process.

How do I deploy a FastAPI app? Serve it with uvicorn — uvicorn main:app --host 0.0.0.0 --port $PORT — because FastAPI is ASGI and plain gunicorn cannot run it. For several cores, use uvicorn main:app --workers 4uvicorn.workers under gunicorn is deprecated. If the app streams responses or holds WebSockets, pick a host that runs a real process rather than one that bills per request.

Can I run Celery on these platforms? On Lizard, Railway, Render, Fly.io, and DigitalOcean App Platform, yes: a Celery worker is a second service with the same image, no HTTP port, and a celery -A myproject worker command. Google Cloud Run fits too, since worker pools reached general availability in April 2026 — they run exactly this kind of long-lived pull-based process. Cloud Run Jobs remains the answer only for batch work that runs and exits.

Is PythonAnywhere still $5 a month? No. In January 2026 PythonAnywhere merged the $5 Hacker plan and the $12 Web Developer plan into one Developer plan at $10 a month. Existing Hacker subscribers who locked in before the cutoff kept the old price; new customers cannot.

Do I need a Dockerfile to deploy a Python app? Not on most platforms. Lizard, Railway, Render, and DigitalOcean App Platform all build from source. Google Cloud Run builds from source too — gcloud run deploy --source . uses Google Cloud's buildpacks when no Dockerfile is present — so AWS Fargate is the one that wants an image. On Lizard, lizardpack writes the Dockerfile on the build node — it picks up uv, poetry, pipenv, or pip from your lockfile and your Python version from .python-version or requires-python.

What is the best free Python hosting? Render's free web service, if you can live with a 15-minute spin-down and about a minute to answer the next request. Google Cloud Run's free tier covers 2 million requests a month and is genuinely free for a quiet API. Lizard starts free with $5 of credit and no card, which covers a small always-on service for the first month.


Sources

Build with AI. Ship with Lizard.

You don't need a platform team to go live. Your whole cloud, one CLI command away.

Try for free

No credit card required

We use cookies for essential site functionality and analytics. See our Cookie Policy.