Deploy a FastAPI App ⚡
Push your FastAPI project to GitHub or GitLab and Faable builds and runs it — no Dockerfile, no YAML, no uvicorn command to write. The builder detects FastAPI from your repo, installs your dependencies, and serves it behind automatic SSL at https://<app>.faable.link, hosted in Europe.
What Faable detects
Detection is file-based (full rules). For FastAPI the builder needs:
| It looks for | Which gives it |
|---|---|
requirements.txt, pyproject.toml or Pipfile | Your dependencies — installed into a virtualenv |
A module defining app = FastAPI(...) | The ASGI entrypoint → the start command below |
It searches for that module in this order, preferring the file that actually defines app:
main.py → app.py → asgi.py → wsgi.py → application.py → server.py → app/main.py → app/app.py → src/main.py
Then it runs, with no configuration from you:
uvicorn <module>:app --host 0.0.0.0 --port $PORTuvicorn is installed automatically if it isn’t in your dependencies — though pinning it is good practice.
The one thing to get right: $PORT
Faable assigns your app a port at runtime and passes it as the PORT environment variable. The auto-detected command already binds 0.0.0.0 and $PORT, so a standard project needs no change. It matters only if you override the start command:
# ✅ Correct — for local runs; on Faable the platform passes the port
import os
import uvicorn
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=int(os.environ.get("PORT", 8000)))Never hardcode port=8000 in the command Faable runs — the app would start and receive no traffic.
A minimal deployable app
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"status": "ok"}
@app.get("/healthz")
def healthz():
return {"ok": True}# requirements.txt
fastapi
uvicorn[standard]That is a complete, deployable repo — two files.
Configuration and secrets
Read configuration from the environment and set it with the CLI or the dashboard:
import os
DATABASE_URL = os.environ["DATABASE_URL"]
ALLOWED_ORIGINS = os.environ.get("ALLOWED_ORIGINS", "").split(",")faable deploy secrets set DATABASE_URL=postgres://… ALLOWED_ORIGINS=https://myapp.faable.linkFaable also injects PORT, FAABLE_APP_ID, FAABLE_RELEASE and FAABLE_GIT_COMMIT — useful for /healthz payloads and error reports. See Environment & Releases.
Deploy
From the dashboard — the normal path:
- Create a Project and an App in the Faable Dashboard .
- Click Link repository and pick your FastAPI repo.
- Push to your release branch. Faable builds and takes it live.
Or from your laptop:
npm i -g @faable/faable
faable login
faable deployYour API is live at https://<app>.faable.link with automatic SSL and the WAF already inspecting traffic. Interactive docs are at /docs if you left them enabled.
Workers and concurrency
The auto-detected command runs a single uvicorn process, and that is the right setting: FastAPI is async, so one process handles many concurrent requests. Leave the worker count to Faable and don’t add --workers to your start command — every worker is a separate process with its own copy of your app and its libraries, so each one multiplies the memory the app needs. To scale up, pick a bigger instance. On the Free plan an app runs at most one worker — see Workers and memory.
Choosing the Python version
A new app gets the newest supported minor — Python 3.14 today — and keeps the minor of its first successful deploy from then on. Supported minors are 3.10, 3.11, 3.12, 3.13 and 3.14 — pin one with a runtime.txt:
python-3.12Or with .python-version, or requires-python in pyproject.toml. First match wins, in that order.
Troubleshooting
- Build fails with “no start command” — the builder installed dependencies but found no module defining
app = FastAPI(...)in the search list. Rename your entrypoint tomain.py, or setstartCommandinfaable.json. - The app starts but requests time out — the start command binds a hardcoded port instead of
$PORT. - CORS errors from your frontend — add
CORSMiddlewareand drive its origins from an environment variable. ModuleNotFoundErrorat boot — the dependency isn’t inrequirements.txt; the build environment installs only what the manifest declares.- A
Dockerfileis being used instead of the Python buildpack — detection order putspackage.json(Node) above Python and Python aboveDockerfile. Force it with{"buildpack": "python"}infaable.json.
FAQ
Do I need a Dockerfile to deploy FastAPI on Faable?
No. Faable finds the module that defines app = FastAPI(...) and generates the uvicorn command for you. A Dockerfile is the escape hatch for stacks the buildpacks don’t detect natively.
How does Faable know which file my FastAPI app is in?
It checks main.py, app.py, asgi.py, wsgi.py, application.py, server.py, app/main.py, app/app.py and src/main.py, preferring the one that actually defines app. If yours lives elsewhere, set startCommand in faable.json.
Can I run FastAPI with multiple uvicorn workers?
You rarely need to. One async process serves many concurrent requests, and each extra worker loads another full copy of your app into memory. Leave the worker count to the command Faable generates, and move to a larger instance for more capacity.
Which Python versions does Faable support for FastAPI?
3.10, 3.11, 3.12, 3.13 and 3.14. A new app gets the newest (3.14 today) and keeps the minor of its first deploy; pin your choice with runtime.txt (python-3.13), .python-version, or requires-python in pyproject.toml.
Does the built-in WAF interfere with API clients?
No. The firewall matches paths, user-agents and query parameter names, never request bodies, so JSON payloads from API clients are not inspected. What it blocks by default are scanner paths no API serves (.env, .git/, *.php…). If a client of yours does get a 403, faable deploy waf list shows the rules in effect — see the WAF guide.
Related
- What the Builder Expects — full detection and start-command rules
- Deploy a WhatsApp Bot · Deploy a Telegram Bot — webhook bots on this stack
- Deploy Next.js · Deploy Django · Deploy Flask · Deploy Node.js Express
- Environment & Releases · Custom domains · WAF
- Secure your API with OAuth 2.0 — Faable Auth is included in the same subscription
Last updated on