DeployxaDocs Portal
CLI v1.0.4
Deploy FastAPI (Python)
Framework guide · FastAPI

Deploy a FastAPI service (Python)

Deploy async FastAPI services with a pip build, Uvicorn serving the ASGI app, a managed PostgreSQL database and HTTPS. The interactive /docs page is live as soon as the release passes its health check.

Prerequisites

  • Python 3.11 or newer locally, and a requirements.txt (or pyproject.toml) listing fastapi and uvicorn.
  • The app object importable from the project root, for example app = FastAPI() in main.py.

How Deployxa detects FastAPI

A requirements.txt, Pipfile or pyproject.toml marks a Python project. Choose the FastAPI preset (or keep Auto-detect) and set the start command explicitly; the generic Python default, python app.py, does not start an ASGI server.

SettingValue
Build commandpip install -r requirements.txt
Start commanduvicorn main:app --host 0.0.0.0 --port 8000
Port8000
RuntimePython 3.11+

Required config: host 0.0.0.0 and the port

Uvicorn binds to 127.0.0.1 by default, which the health check cannot reach. Always pass --host 0.0.0.0, and a port that matches the service's Internal Port. To follow a PORT variable instead of a fixed number, run it through a shell:

shell
# fixed port (matches the preset)
uvicorn main:app --host 0.0.0.0 --port 8000

# follow $PORT, default 8000, with 2 worker processes
sh -c 'uvicorn main:app --host 0.0.0.0 --port ${PORT:-8000} --workers 2 --proxy-headers --forwarded-allow-ips="*"'

--proxy-headers with --forwarded-allow-ips makes request.url use https behind the proxy, so redirects and generated links are correct.

python
# main.py
import os
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI(title="My API")
app.add_middleware(
    CORSMiddleware,
    allow_origins=[o for o in os.getenv("CORS_ORIGINS", "").split(",") if o],
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/health")
def health():
    return {"ok": True}

Environment variables

KeyPurposeExample
DATABASE_URLInjected when PostgreSQL is attachedpostgresql://…
CORS_ORIGINSAllowed browser originshttps://app.example.com
SECRET_KEYToken signing keya long random string

Databases and migrations

In the wizard's Configure step, set Database to PostgreSQL. The connection string is injected into the app as DATABASE_URL, so nothing needs to be committed. Choose SQLite only for small apps: it lives on a persistent volume and has no server.

For async SQLAlchemy, swap the scheme to the asyncpg driver in code, so the injected value can stay as it is:

python
# db.py
import os
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

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

engine = create_async_engine(url, pool_size=5, pool_pre_ping=True)
SessionLocal = async_sessionmaker(engine, expire_on_commit=False)

Run Alembic before the server so the schema is current when traffic switches: sh -c 'alembic upgrade head && uvicorn main:app --host 0.0.0.0 --port 8000'.

Deploy

From the dashboard

  1. 1
    Source

    Open Dashboard → Projects → New project (/dashboard/projects/new). Pick the GitHub repository and branch, or upload a .zip archive of the project.

  2. 2
    Configure

    Leave the framework preset on Auto-detect or choose FastAPI. Check the fields under advanced settings:

    • Build command: pip install -r requirements.txt
    • Root directory: ./, or the sub-folder that holds the app in a monorepo
    • Database: PostgreSQL
  3. 3
    Environment

    Add your variables in the table, or paste a whole .env file into the Bulk / .env tab.

  4. 4
    Deploy

    Start the deploy and watch the build log. When the release passes its health check it is served over HTTPS on its Deployxa URL.

  5. 5
    Confirm the start command and port

    Open the project's Environment Canvas tab and select the web service. Set Start Command to uvicorn main:app --host 0.0.0.0 --port 8000. Set Internal Port to 8000 so it matches the port your app listens on. Save and redeploy if you changed anything.

From the CLI

shell
$ npm install -g @deployxa/cli
$ deployxa login
$ cd my-app
$ deployxa link            # pick an existing project, or skip: deploy creates one
$ deployxa env set CORS_ORIGINS "https://app.example.com"
$ deployxa deploy
$ deployxa logs --live     # stream build and runtime logs
$ deployxa open            # open the live URL

If the folder is not linked, deployxa deploy creates a project named after the folder and links it (the link is saved in .deployxa/config.json). Later runs deploy the linked project. deployxa status shows the latest deployment and deployxa rollback previous returns to the release before it.

Warning: deployxa deploy packages the folder exactly as it is on disk; it does not read .gitignore. Delete local node_modules, virtualenvs, build output and real .env files first, or deploy from a clean clone. Set secrets with deployxa env set instead of shipping them in the archive.

deployxa create fastapi scaffolds a minimal FastAPI starter if you want to try the flow first.

Custom domain

Go to Dashboard → Domains, choose Connect a domain you already own and pick this project. Deployxa then shows the DNS records to create at your DNS provider:

RecordUse it forValue
AAn apex domain such as example.com85.17.244.184 (DNS only on Cloudflare)
CNAMEA subdomain such as www or appcname.deployxa.com (DNS only on Cloudflare)
TXTOnly when a CDN or proxy (for example Cloudflare orange-cloud) hides the origin recordHost _deployxa-challenge.<your-domain>, value deployxa-verification=…

DNS changes can take several minutes to propagate; use Retry verification once they have. A Let's Encrypt certificate is issued after the domain verifies. From a linked folder you can do the same with the CLI:

shell
$ deployxa domains add app.example.com
$ deployxa dns             # Waiting → Verified → SSL Active
$ deployxa domains list

Common errors and fixes

SymptomFix
Health check fails; log says "Uvicorn running on http://127.0.0.1:8000"Add --host 0.0.0.0.
Error loading ASGI app. Could not import module "main"The module path is wrong. Use package.module:app relative to the root directory, e.g. app.main:app.
ModuleNotFoundError at startupThe package is missing from requirements.txt; regenerate it or add it and redeploy.
sqlalchemy: Can't load plugin: sqlalchemy.dialects:postgresReplace the postgres:// scheme with postgresql:// (or postgresql+asyncpg://).
Redirects go to http://Start Uvicorn with --proxy-headers --forwarded-allow-ips="*".

Start with deployxa logs --live (or the deployment's log view in the dashboard): the build log shows dependency and compile failures, the runtime log shows crashes and bind errors. See also Troubleshooting.