EthioDeploy/Docs
HomePricing
Overview

Overview

  • Getting started
  • How deploys work

Frameworks

  • Framework guides

Configuration

  • Web services & background workers
  • Environment variables
  • Addons
  • Database & Redis tools
  • Branch deployments
  • Custom domains
  • Analytics

Domains

  • Buying a domain

Agent mode

  • Agent mode
  • Agent plans & credit

CLI

  • Command-line tool

Account

  • Team access
  • Billing

Help

  • Troubleshooting
  • Still stuck?
Deploy guides
  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor
Compare
  • AI coding agent
  • Hosting in Ethiopia
  • vs Heroku
  • vs Vercel
  • vs Render
  • vs Railway
  • vs Fly.io
  • vs Netlify
  • Heroku alternatives
Deploy guidesFastAPI

Deploy a FastAPI app

FastAPI deploys from requirements.txt or pyproject.toml. Set a start command with fastapi run, add a health route, and push. Postgres is one click away.

Last updated October 23, 2026

Detected by
requirements.txt, pyproject.toml, Pipfile or main.py
Install
pip install -r requirements.txt (or poetry / uv / pdm)
Build
none by default
Start
python main.py (set your own)

These are the defaults. Override any of them in Settings → Build.

Set a start command: the default only runs python main.py

Without a start command we run python main.py, which serves nothing unless that file starts uvicorn itself. Set the Start command in Settings → Build to fastapi run main.py --port $PORT. fastapi run listens on 0.0.0.0 by default.

Prepare your app

Install FastAPI with its standard extras, which include the fastapi CLI and uvicorn:

fastapi[standard]

Then set the Start command to one of:

# app in main.py
fastapi run main.py --port $PORT

# app in app/main.py, two worker processes (Pro and above)
fastapi run app/main.py --port $PORT --workers 2

# plain uvicorn
uvicorn app.main:app --host 0.0.0.0 --port $PORT

Pin the Python version with a .python-version file. A Procfile web: line also works as the start command.

HTTPS behind the proxy

HTTPS ends at the platform's proxy, which forwards requests to your app over HTTP with an X-Forwarded-Proto header. Uvicorn only trusts that header from 127.0.0.1 by default, so redirects FastAPI generates (like the trailing-slash redirect from /items to /items/) point at http:// and browsers block them as mixed content.

Add the env var FORWARDED_ALLOW_IPS=*. Uvicorn and fastapi run both read it.

Add a health route

Every deploy requests your health check path (/ by default) and only goes live once it returns a 2xx or 3xx status. The platform keeps checking it after that. If / returns 404 or needs a login, add a route like /healthz that returns 200 and set it as the Health Check Path in Settings. Otherwise the deploy fails and the previous version keeps serving.

@app.get("/healthz", include_in_schema=False)
def healthz():
    return {"ok": True}

Environment variables

Add variables in the project's settings. They're available both while the app builds and while it runs, so build-time values (like framework-public keys) work without extra setup. See Environment variables. Read them with os.environ or pydantic-settings' BaseSettings. A .env file in the repo isn't needed in production.

Add a database

Add a Postgres addon and DATABASE_URL is injected automatically. It uses the postgres:// scheme, which SQLAlchemy 2.x rejects, so rewrite it for the driver you use:

import os
from sqlalchemy.ext.asyncio import create_async_engine

url = os.environ["DATABASE_URL"].replace("postgres://", "postgresql+asyncpg://", 1)
engine = create_async_engine(url, pool_size=5)

Use postgresql+psycopg:// instead for a sync engine. Run Alembic migrations before the server starts:

alembic upgrade head && fastapi run main.py --port $PORT

Background work

FastAPI's BackgroundTasks run inside the same process and need nothing extra. For a queue (ARQ, Celery, Dramatiq), add a Redis addon and start the worker in the same container, for example arq app.worker.WorkerSettings & fastapi run main.py --port $PORT. Addons are private to their project, so a separate worker project can't reach them.

Deploy

  1. Sign in with GitHub and install the EthioDeploy app on the repo.
  2. Click “New Project” and pick the repo.
  3. Watch the build in the dashboard. When the health check passes, your app is live at <project-slug>.ethiodeploy.com. Every push to the default branch redeploys, and the old version keeps serving until the new one is healthy.

Troubleshooting

Deploy fails the health check, or the app exits right after starting

Cause: No start command, so python main.py ran and didn't start a server.

Fix: Set the Start command to fastapi run main.py --port $PORT.

Deploy fails: GET / returned 404

Cause: The app has no / route, so the health check never passes.

Fix: Add a /healthz route and set it as the Health Check Path.

Redirects go to http:// and the browser blocks them

Cause: Uvicorn doesn't trust the proxy's X-Forwarded-Proto header.

Fix: Set FORWARDED_ALLOW_IPS=*.

NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres

Cause: SQLAlchemy 2.x doesn't accept the postgres:// scheme.

Fix: Replace it with postgresql+asyncpg:// or postgresql+psycopg:// before creating the engine.

Container restarts under load on the Free plan

Cause: Several workers don't fit in 256 MB of memory.

Fix: Run a single worker on Free, or move to Pro for 1 GB.

Still stuck? Check the deployment's build log in the dashboard, or see Troubleshooting.

Questions

Can I deploy a FastAPI app for free?

Yes. The Free plan runs one project with a 512 MB Postgres database. It sleeps after 30 minutes without traffic and wakes on the next request. Pro ($10/month) is always on with 1 GB of memory.

Should I use fastapi run or uvicorn?

Either works. fastapi run is uvicorn with production defaults and listens on 0.0.0.0. Pass --port $PORT to both.

Can I use WebSockets?

Yes. The app runs as a normal long-lived process, so WebSocket endpoints work like they do locally.

Is the /docs page public?

Yes, unless you turn it off. Pass docs_url=None and redoc_url=None to FastAPI() in production if you don't want the API docs exposed.

Ready to deploy? Sign in with GitHub and pick your repo. No Dockerfile, no YAML.

Other framework guides

Next.jsNode.jsPythonSvelteKitLovableBoltClaude Code & CursorDjangoFlaskLaravelExpressGoFirebase Studio

See the full docs for custom domains, env vars, addons, and billing.

On this page

  • Prepare your app
  • HTTPS behind the proxy
  • Add a health route
  • Environment variables
  • Add a database
  • Background work
  • Deploy
  • Troubleshooting
  • Questions

Product

  • Pricing
  • Documentation
  • AI coding agent
  • Agent mode docs
  • Domains
  • Hosting in Ethiopia

Deploy guides

  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Firebase Studio
  • Claude Code & Cursor

Compare

  • EthioDeploy vs Heroku
  • EthioDeploy vs Vercel
  • EthioDeploy vs Render
  • EthioDeploy vs Railway
  • EthioDeploy vs Fly.io
  • EthioDeploy vs Netlify
  • Heroku alternatives

Company

  • About
  • Support
  • Contact
  • Terms
  • Privacy

EthioDeploy: agentic first development and deployment, started in Ethiopia, built for developers everywhere.