Deploy FastAPI HA [Nov '26]

FastAPI on Python 3.15 + uv over self-healing PostgreSQL HA with failover

Deploy FastAPI HA [Nov '26]

Just deployed

Just deployed

/data

Just deployed

/data

Just deployed

/data

Deploy and Host FastAPI HA

Deploy FastAPI HA on Railway and get a production-ready Python 3.15 API backed by self-healing PostgreSQL: automated failover, a streaming read replica, Alembic migrations, health probes, and OpenTelemetry telemetry in one click.

About Hosting

Hosting FastAPI HA on Railway pairs the lean FastAPI starter stack (uv-locked Python 3.15, hardened multi-stage image, JSON logging, native OTel) with our own pg_auto_failover cluster: a monitor, a primary, and a hot standby that clones via WAL streaming. The app connects through a multi-host URL pinned to read-write sessions, so when the monitor promotes the standby your API keeps writing — seconds of blip instead of an outage. Nodes talk over Railway's private network only; nothing database-facing is exposed to the internet.

Why Deploy FastAPI HA on Railway?

This template wires the full production path for you: a three-node PostgreSQL 18 HA cluster (same battle-tested image as our standalone Postgres HA template), a failover-aware connection string auto-composed over the private network, additive Alembic migrations that always target the read-write primary, split liveness/readiness probes, and native OpenTelemetry traces/metrics/logs in Railway's Observability tab. Sleep-at-night durability for APIs that cannot tolerate database downtime — plus a read replica you can point analytics traffic at.

What's included

ServiceTypePurpose
fastapiWeb ServiceThe FastAPI app: async SQLModel, Alembic on boot, health probes
pgaf-primaryDatabasePostgreSQL 18 primary (writes) with persistent volume
pgaf-replicaDatabaseStreaming hot standby (reads, promotion candidate)
pgaf-monitorDatabasepg_auto_failover arbiter: health checks + automated promotion

Key features

  • Self-healing Postgres: monitor detects primary failure (~10s), promotes the standby — no human intervention, no DNS tricks
  • Automatic rejoin: a returned old primary is demoted and re-cloned; no split-brain, no manual pg_rewind
  • Failover-aware app wiring: multi-host DATABASE_URL with target_session_attrs=read-write; migrations and writes always land on the live primary
  • Read scaling: point reporting queries at pgaf-replica to keep the primary free for writes
  • Latest app stack: FastAPI 0.162.4 on Python 3.15.2, uv-locked, /healthz + /readyz probes, JSON logging, native OTel, WEB_CONCURRENCY scaling

Common Use Cases

  • Production API that cannot tolerate database downtime (failover in seconds)
  • Read-heavy workloads: writes to the primary, analytics offloaded to the hot standby
  • Zero-downtime maintenance windows (fail over, patch, fail back)
  • Teams wanting a HA Postgres backend wired into FastAPI without hand-rolling topology

Dependencies for FastAPI HA

Deployment Dependencies

NameVersionPurpose
Python3.15.2Runtime (latest stable)
FastAPI0.162.4Web framework (pinned)
uvicorn / fastapi-clilocked in uv.lockASGI server via the official fastapi run CLI
SQLModel + SQLAlchemy asynclockedORM over asyncpg (multi-host failover DSNs)
AlembiclockedVersioned, additive migrations (read-write targeted)
PostgreSQL + pg_auto_failover18 (our image)Three-node HA cluster: monitor, primary, replica

Next steps

  1. Open the service domain and visit /docs — the interactive Swagger UI with the reference CRUD at /api/v1/items
  2. Create an item via POST /api/v1/items — it lands on the primary and streams to the replica
  3. Open the Observability tab and watch request spans arrive via OpenTelemetry
  4. Test failover safely: stop pgaf-primary, watch the monitor promote the replica, and keep writing — no reconnect needed

🐍 Deep Dive — FastAPI HA

📐 Architecture

graph TD
    Client([Client / Frontend]) --> Gateway[Railway Public Domain + TLS]
    Gateway --&gt; Web[fastapi service<br>Python 3.15 · uvicorn workers]
    Web --&gt;|writes / target read-write| Primary[pgaf-primary]
    Web --&gt;|optional reads| Replica[pgaf-replica]
    Monitor[pgaf-monitor] &lt;--&gt;|health checks + promotion| Primary
    Monitor &lt;--&gt;|health checks| Replica
    Primary --&gt;|WAL streaming| Replica
    Web --&gt; OTel[Railway Observability<br>OTLP traces · metrics · logs]

⚙️ Environment Variables

Wired automatically (no input needed): DATABASE_URL is a multi-host failover URL composed from the cluster's private domains — postgresql://postgres@${{pgaf-primary.RAILWAY_PRIVATE_DOMAIN}}:5432,${{pgaf-replica.RAILWAY_PRIVATE_DOMAIN}}:5432/postgres?target_session_attrs=read-write. Set DATABASE_URL explicitly to use an external database instead.

User-configurable:

VariableDefaultDescription
PORT8000Injected by Railway; the entrypoint binds it automatically.
WEB_CONCURRENCY2Uvicorn workers (read natively by the FastAPI CLI). Scale with CPU.
ENVIRONMENTproductionEnvironment label (production, staging, …).
LOG_LEVELinfodebug · info · warning · error — logs ship as JSON.
BACKEND_CORS_ORIGINS(empty)Comma-separated allowed CORS origins.
RUN_MIGRATIONStrueRun alembic upgrade head before serving (targets the read-write primary).
DB_POOL_SIZE / DB_MAX_OVERFLOW10 / 10Async connection pool tuning.
FASTAPI_OTEL_AUTO_CONFIGUREtrueNative OTel export (active when Railway's OTLP endpoint is present).

How failover works

  1. pgaf-monitor health-checks the primary every second.
  2. On ~10s of failures it promotes the standby — the new primary.
  3. The app's multi-host URL (target_session_attrs=read-write) reconnects writes to whichever node is read-write — transparent failover, no config change.
  4. The old primary returns → demoted and re-cloned as the new standby. Roles converge without manual action.

🚀 Local Development

Prerequisites: uv (installs Python 3.15 automatically).

git clone  &amp;&amp; cd fastapi-ha
cp .env.example .env

uv sync --all-groups          # resolves uv.lock exactly
uv run fastapi dev            # hot-reload dev server on :8000
uv run pytest                 # test suite (async SQLite — no Postgres needed)
uv run alembic upgrade head   # apply migrations locally

Handy commands:

uv run alembic revision --autogenerate -m "add orders table"   # new migration
uv lock &amp;&amp; uv sync --all-groups                                # after dependency changes
bash e2e/run-tests.sh                                          # full template validation

Shipping to Railway

railway init    # or link an existing project
railway up      # builds from the Dockerfile (config-as-code in railway.toml)

🩺 Health & Observability

EndpointPurposeBehavior
/healthzLiveness (Railway healthcheckPath)Cheap JSON 200 — never touches the DB.
/readyzReadinessSELECT 1 round-trip through the failover URL; 503 when no writable node.
/docs, /redocInteractive API docsAuto-generated OpenAPI.
/api/v1/itemsReference CRUDCopy this pattern for your own resources.

🧱 Building Your Own API on Top

  1. New resource → copy the app/db/models/item.py split (Base → table → Create/Update/Public), then uv run alembic revision --autogenerate -m "…".
  2. New endpoints → add a router under app/api/routes/, include it in app/main.py.
  3. New config → add the field to app/core/config.py; it becomes an env var automatically.
  4. Migrations stay additive — nullable columns first, chunked backfills, CREATE INDEX CONCURRENTLY on live tables (zero-downtime policy).

🧪 End-to-End (E2E) Testing

bash e2e/run-tests.sh

Validates structure, marketplace publish config, manifest wiring (HA cluster → multi-host DATABASE_URL with read-write targeting), uv.lock freshness, byte-compilation, pytest, Docker build, and a live container smoke probe of /healthz + /docs. CI runs hadolint + this suite on every push/PR.


Maintained by the template publisher. Deployments are eligible for Railway's standard template support flow — questions land in the publisher's Template Queue.


Template Content

More templates in this category

View Template
Openfront Gym
Opensource Mindbody alternative based on Next.js and Keystone.js

Openship
0
View Template
open-excalidraw
Self-hostable collaborative drawing built on Excalidraw

Prateek Mohanty
5
View Template
Next.js + Prisma + PostgreSQL Starter
Deploy a Next.js app with Prisma ORM and PostgreSQL in one click.

blueorange
0