Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,53 @@
<a href="https://github.com/fastapi/full-stack-fastapi-template/actions?query=workflow%3A%22Test+Backend%22" target="_blank"><img src="https://github.com/fastapi/full-stack-fastapi-template/workflows/Test%20Backend/badge.svg" alt="Test Backend"></a>
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/full-stack-fastapi-template" target="_blank"><img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/full-stack-fastapi-template.svg" alt="Coverage"></a>

## Deploy to Render

[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/fastapi/full-stack-fastapi-template)

One click provisions the full stack on [Render](https://render.com) using the [`render.yaml`](./render.yaml) Blueprint at the repo root: a Dockerized FastAPI web service, a Vite/Bun static site for the frontend, a managed Postgres database, and a shared `fastapi-env` environment-variable group that both services pull from.

### Setup after clicking the button

1. **Fill in the secret env vars on `fastapi-backend`** (Dashboard → `fastapi-backend` → Environment):
- `FIRST_SUPERUSER` — admin email, e.g. `admin@yourdomain.com`
- `FIRST_SUPERUSER_PASSWORD` — generate one with `python -c "import secrets; print(secrets.token_urlsafe(32))"`
- Optional: `SMTP_HOST` / `SMTP_USER` / `SMTP_PASSWORD` / `EMAILS_FROM_EMAIL` (if you want password-reset emails) and `SENTRY_DSN` (if using Sentry)

`SECRET_KEY` and all `POSTGRES_*` vars are set automatically. `ENVIRONMENT`, `PROJECT_NAME`, `STACK_NAME`, and the `SMTP_TLS/SSL/PORT` defaults come from the `fastapi-env` env group — no action needed.

> **Note:** secrets live on the service (not the env group) because Render's env groups don't accept `sync: false` placeholders. The `fastapi-env` group only holds shared, non-secret defaults; everything secret or service-specific is set directly on `fastapi-backend` or `fastapi-frontend`.

2. **Wait for both services to finish deploying** so they're assigned `.onrender.com` URLs.

3. **Set the cross-service URLs on the appropriate services** (these can only be set after the first deploy, since they depend on the assigned hostnames):
- `VITE_API_URL` → set on **`fastapi-frontend`** → Environment, to the **backend** URL, e.g. `https://fastapi-backend-XXXX.onrender.com`. *Baked into the frontend bundle at build time.*
- `FRONTEND_HOST` → set on **`fastapi-backend`** → Environment, to the **frontend** URL, e.g. `https://fastapi-frontend-XXXX.onrender.com`. *Auto-appended to the backend's CORS allowlist at runtime.*
- `BACKEND_CORS_ORIGINS` → set on **`fastapi-backend`** → Environment, comma-separated list of additional allowed origins (you can usually leave this empty since `FRONTEND_HOST` already covers the frontend).

4. **Trigger a manual rebuild of the frontend** (Dashboard → `fastapi-frontend` → Manual Deploy → Clear build cache & deploy). `VITE_API_URL` is baked into the bundle at build time, so an existing build won't pick up the new value until rebuilt.

## Technology Stack and Features

- [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
- 🚀 [React](https://react.dev) for the frontend.
- 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack.
- 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components.
- 🤖 An automatically generated frontend client.
- 🧪 [Playwright](https://playwright.dev) for End-to-End testing.
- 🦇 Dark mode support.
- 🐋 [Docker Compose](https://www.docker.com) for development and production.
- 🔒 Secure password hashing by default.
- 🔑 JWT (JSON Web Token) authentication.
- 📫 Email based password recovery.
- 📬 [Mailcatcher](https://mailcatcher.me) for local email testing during development.
- Tests with [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer.
- 🚢 Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates.
- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.
- [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.
- [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- [PostgreSQL](https://www.postgresql.org) as the SQL database.
- [React](https://react.dev) for the frontend.
- Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack.
- [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components.
- An automatically generated frontend client.
- [Playwright](https://playwright.dev) for End-to-End testing.
- Dark mode support.
- [Docker Compose](https://www.docker.com) for development and production.
- Secure password hashing by default.
- JWT (JSON Web Token) authentication.
- Email based password recovery.
- [Mailcatcher](https://mailcatcher.me) for local email testing during development.
- Tests with [Pytest](https://pytest.org).
- [Traefik](https://traefik.io) as a reverse proxy / load balancer.
- Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates.
- CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.

### Dashboard Login

Expand Down
4 changes: 4 additions & 0 deletions backend/scripts/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
bash scripts/prestart.sh
exec fastapi run --workers "${WEB_CONCURRENCY:-1}" --host 0.0.0.0 --port "$PORT" app/main.py
95 changes: 95 additions & 0 deletions render.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
envVarGroups:
- name: fastapi-env
envVars:
- key: ENVIRONMENT
value: production
- key: PROJECT_NAME
value: "Full Stack FastAPI"
- key: STACK_NAME
value: fastapi-project
- key: SMTP_TLS
value: "true"
- key: SMTP_SSL
value: "false"
- key: SMTP_PORT
value: "587"

projects:
- name: full-stack-fastapi-template
environments:
- name: production
services:
- type: web
name: fastapi-backend
runtime: docker
plan: free
repo: https://github.com/fastapi/full-stack-fastapi-template
branch: main
autoDeploy: true
dockerfilePath: ./backend/Dockerfile
dockerContext: .
dockerCommand: bash scripts/start.sh
healthCheckPath: /api/v1/utils/health-check/
envVars:
- fromGroup: fastapi-env
- key: SECRET_KEY
generateValue: true
- key: POSTGRES_SERVER
fromDatabase:
name: fastapi-db
property: host
- key: POSTGRES_PORT
fromDatabase:
name: fastapi-db
property: port
- key: POSTGRES_USER
fromDatabase:
name: fastapi-db
property: user
- key: POSTGRES_PASSWORD
fromDatabase:
name: fastapi-db
property: password
- key: POSTGRES_DB
fromDatabase:
name: fastapi-db
property: database
- key: FIRST_SUPERUSER
sync: false
- key: FIRST_SUPERUSER_PASSWORD
sync: false
- key: FRONTEND_HOST
sync: false
- key: BACKEND_CORS_ORIGINS
sync: false
- key: SMTP_HOST
sync: false
- key: SMTP_USER
sync: false
- key: SMTP_PASSWORD
sync: false
- key: EMAILS_FROM_EMAIL
sync: false
- key: SENTRY_DSN
sync: false

- type: web
name: fastapi-frontend
runtime: static
repo: https://github.com/fastapi/full-stack-fastapi-template
branch: main
autoDeploy: true
buildCommand: bun install --frozen-lockfile && bun run --filter frontend build
staticPublishPath: frontend/dist
routes:
- type: rewrite
source: /*
destination: /index.html
envVars:
- key: VITE_API_URL
sync: false

databases:
- name: fastapi-db
databaseName: app
plan: free
Loading