Deploy FastAPI Starter

FastAPI on Python 3.15 + uv: Postgres, Alembic, OTel, health probes

Deploy FastAPI Starter

Just deployed

Just deployed

/var/lib/postgresql/data

Deploy and Host FastAPI

Deploy this FastAPI Starter on Railway and get a production-ready Python 3.15 API with PostgreSQL, Alembic migrations, health probes, and OpenTelemetry telemetry in one click.

About Hosting

Hosting FastAPI on Railway gives you a managed, usage-based platform for your Python API: automatic TLS, deploys from prebuilt images, vertical and horizontal scaling, built-in observability, and a bundled PostgreSQL 18 database (our hardened image with essential extensions) provisioned alongside your app. This starter runs on the latest stable Python (3.15) with a uv-locked dependency tree, runs database migrations before serving traffic, and reports liveness/readiness so Railway only routes traffic to healthy instances.

Why Deploy FastAPI Starter on Railway?

This template wires the full production path for you: a hardened multi-stage Docker image (non-root, slim), a bundled PostgreSQL 18 service from our own hardened image (persistent volume, extensions preloaded) with the connection string auto-composed over Railway's private network, additive Alembic migrations executed on boot, native OpenTelemetry traces/metrics/logs flowing into Railway's Observability tab, and JSON structured logging out of the box. Instead of wiring a framework version, database, migrations, health checks, and telemetry yourself, deploy once and start writing endpoints — the reference CRUD resource shows the pattern to copy.

What's included

| Service | Type | Purpose | | --- | --- | | fastapi | Web Service | The FastAPI app: async SQLModel, Alembic on boot, health probes | | Postgres | Database | PostgreSQL 18 (our hardened image, persistent volume); connection URL auto-composed as DATABASE_URL |

Key features

  • Latest stack: FastAPI 0.162.4 on Python 3.15.2, uv-locked for reproducible builds
  • PostgreSQL + Alembic: bundled PostgreSQL 18 service (persistent volume, extensions preloaded), additive migrations run before serving
  • Health probes: /healthz liveness (Railway healthcheck) and /readyz DB readiness
  • Native OpenTelemetry: traces, metrics, and logs export to Railway's OTLP collector — no code needed
  • Production hygiene: non-root multi-stage image, JSON logging, WEB_CONCURRENCY worker scaling, graceful shutdown

Common Use Cases

  • Backend developer launches a production FastAPI API with Postgres in one click
  • Team standardizes on a modern, pinned Python API starter with observability built in
  • Solo dev prototypes an API locally (uv + SQLite) and ships the same code to Railway
  • Anyone needing a reference for async SQLModel, Alembic zero-downtime migrations, and health-probe patterns

Dependencies for FastAPI

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
AlembiclockedVersioned, additive migrations
PostgreSQL18 (our image)Bundled database service with persistent volume

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, then list with GET /api/v1/items
  3. Open the Observability tab and watch request spans arrive via OpenTelemetry
  4. Copy app/db/models/item.py + app/api/routes/items.py to add your own resources, then autogenerate a migration

🐍 Deep Dive — FastAPI Starter

📐 Architecture

graph TD
    Client([Client / Frontend]) --> Gateway[Railway Public Domain + TLS]
    Gateway --&gt; Web[fastapi service<br>Python 3.15 · uvicorn workers]
    Web --&gt; PG[(Postgres service<br>auto-provisioned)]
    Web --&gt; OTel[Railway Observability<br>OTLP traces · metrics · logs]

⚙️ Environment Variables

Wired automatically (no input needed): DATABASE_URL is composed from the bundled Postgres service credentials — postgresql://${{Postgres.POSTGRES_USER}}:${{Postgres.POSTGRES_PASSWORD}}@${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5432/${{Postgres.POSTGRES_DB}} — and normalized to the asyncpg driver at runtime. 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.
DB_POOL_SIZE / DB_MAX_OVERFLOW10 / 10Async connection pool tuning.
FASTAPI_OTEL_AUTO_CONFIGUREtrueNative OTel export (active when Railway's OTLP endpoint is present).

🚀 Local Development

Prerequisites: uv (installs Python 3.15 automatically).

git clone  &amp;&amp; cd fastapi
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; 503 when the DB is down.
/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 (Postgres → DATABASE_URL), 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