full-stack-fastapi-template Documentation

Full-stack web application template with FastAPI, React, SQLModel, PostgreSQL, Vite, Tailwind CSS, shadcn/ui, FastAPI Cloud, and Docker Compose.

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy full-stack-fastapi-template on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name full-stack-fastapi-template --restart always postgres:18
Configured Services & Ports
โš™๏ธ proxy
image: traefik:v3.7
โš™๏ธ db
image: postgres:18
โš™๏ธ adminer
image: adminer
โš™๏ธ backend
image: backend:latest
docker-compose.yml
yaml (docker-compose.yml)
services:

  proxy:
    image: traefik:v3.7
    volumes:
      # Add Docker as a mounted volume, so that Traefik can read the labels of other services
      - /var/run/docker.sock:/var/run/docker.sock:ro
    command:
      # Enable Docker in Traefik, so that it reads labels from Docker services
      - --providers.docker
      # Do not expose all Docker services, only the ones explicitly exposed
      - --providers.docker.exposedbydefault=false
      # Create an entrypoint "http" listening on port 80
      - --entrypoints.http.address=:80
      # Enable the access log, with HTTP requests
      - --accesslog
      # Enable the Traefik log, for configurations and errors
      - --log

  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d app"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s
    volumes:
      - app-db-data:/var/lib/postgresql
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?Variable not set}
      - POSTGRES_DB=app

  adminer:
    image: adminer
    depends_on:
      - db
    environment:
      - ADMINER_DESIGN=pepa-linha-dark
    labels:
      # Enable Traefik for this service
      - traefik.enable=true
      # Route HTTP traffic for the Adminer subdomain
      - traefik.http.routers.adminer-http.rule=Host(`adminer.${DOMAIN:-localhost}`)
      - traefik.http.routers.adminer-http.entrypoints=http
      # Define the port inside of the Docker service to use
      - traefik.http.services.adminer.loadbalancer.server.port=8080

  backend:
    image: backend:latest
    depends_on:
      db:
        condition: service_healthy
        restart: true
    environment:
      PROJECT_NAME: ${PROJECT_NAME:?Variable not set}
      SECRET_KEY: ${SECRET_KEY:?Variable not set}
      FIRST_SUPERUSER: ${FIRST_SUPERUSER:?Variable not set}
      FIRST_SUPERUSER_PASSWORD: ${FIRST_SUPERUSER_PASSWORD:?Variable not set}
      SMTP_HOST: ${SMTP_HOST}
      SMTP_USER: ${SMTP_USER:-}
      SMTP_PASSWORD: ${SMTP_PASSWORD:-}
      EMAILS_FROM_EMAIL: ${EMAILS_FROM_EMAIL}
      DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:?Variable not set}@db:5432/app
      SENTRY_DSN: ${SENTRY_DSN:-}

    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/utils/health-check/"]
      interval: 10s
      timeout: 5s
      retries: 5

    build:
      context: .
      dockerfile: backend/Dockerfile
    labels:
      # Enable Traefik for this service
      - traefik.enable=true

      # Define the port inside of the Docker service to use
      - traefik.http.services.backend.loadbalancer.server.port=8000

      # Route HTTP traffic for this domain
      - traefik.http.routers.backend-http.rule=Host(`${DOMAIN:-localhost}`)
      - traefik.http.routers.backend-http.entrypoints=http

volumes:
  app-db-data:

File: README.md

Full Stack FastAPI Template


Technology Stack and Features

  • โšก FastAPI for the Python backend API.
    • ๐Ÿงฐ SQLModel for the Python SQL database interactions (ORM).
    • ๐Ÿ” Pydantic, used by FastAPI, for the data validation and settings management.
    • ๐Ÿ’พ PostgreSQL as the SQL database.
  • ๐Ÿš€ React for the frontend.
    • ๐Ÿงฉ Built into the backend application and served by FastAPI on the same domain as the API.
    • ๐Ÿ’ƒ Using TypeScript, hooks, Vite, and other parts of a modern frontend stack.
    • ๐ŸŽจ Tailwind CSS and shadcn/ui for the frontend components.
    • ๐Ÿค– An automatically generated frontend client.
    • ๐Ÿงช Playwright for end-to-end testing.
    • ๐Ÿฆ‡ Dark mode support.
  • โ˜๏ธ FastAPI Cloud for deployment.
  • ๐Ÿ‹ Docker Compose for local services and self-hosted deployment.
    • ๐Ÿ“ž Traefik as a reverse proxy with automatic HTTPS.
  • ๐Ÿ”’ Secure password hashing by default.
  • ๐Ÿ”‘ JWT (JSON Web Token) authentication.
  • ๐Ÿ“ซ Email-based password recovery.
  • ๐Ÿ“ฌ Mailpit for local email testing during development.
  • โœ… Tests with Pytest.
  • ๐Ÿญ CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.

Dashboard Login

Dashboard - Admin

Dashboard - Items

Dashboard - Dark Mode

Interactive API Documentation

How to Use It

Click the Use this template button at the top of this page to create a new repository.

Backend Development

Backend docs: backend/README.md.

Frontend Development

Frontend docs: frontend/README.md.

Deployment

FastAPI Cloud deployment: deployment.md.

Self-hosted deployment with Docker Compose: deployment-docker-compose.md.

Development

General development docs: development.md.

This includes the local FastAPI and Vite workflow, Docker Compose services, .env configuration, and more.

Release Notes

Check the file release-notes.md.

License

The Full Stack FastAPI Template is licensed under the terms of the MIT license.


File: backend/README.md

FastAPI Project - Backend

Requirements

  • Docker.
  • uv for Python package and environment management.

Local Development

Run the backend locally and connect it to PostgreSQL in Docker Compose.

From the project root, start PostgreSQL and Mailpit:

console
$ docker compose up -d db mailpit

Then, from ./backend/, install the dependencies, prepare the database, and start the development server:

console
$ uv sync
$ uv run bash scripts/prestart.sh
$ uv run fastapi dev

The API is available at http://localhost:8000, with automatic interactive docs at http://localhost:8000/docs.

General Workflow

Run backend commands from ./backend/ with uv run. Make sure your editor uses the Python interpreter at .venv/bin/python in the project root.

Modify or add SQLModel models for data and SQL tables in ./backend/app/models.py, API endpoints in ./backend/app/api/, CRUD (Create, Read, Update, Delete) utils in ./backend/app/crud.py.

VS Code

There are already configurations in place to run the backend through the VS Code debugger, so that you can use breakpoints, pause and explore variables, etc.

The setup is also already configured so you can run the tests through the VS Code Python tests tab.

Full Stack with Docker Compose

To run the backend and built frontend in Docker Compose:

console
$ docker compose run --rm backend bash scripts/prestart.sh
$ docker compose watch

The application is available at http://localhost:8000.

Docker Compose Override

The compose.override.yml file contains local settings for published ports, source synchronization, automatic image rebuilds, and backend reloads. Docker Compose applies it automatically when you run docker compose without an explicit file list.

To open a shell in the backend container:

console
$ docker compose exec backend bash

Backend Tests

To test the backend from the backend directory, run:

console
$ uv run bash scripts/test.sh

The tests run with Pytest. Modify existing tests or add new ones in ./backend/tests/.

If you use GitHub Actions, the tests will run automatically.

Test a Running Stack

If your stack is already up and you just want to run the tests, you can use:

bash
docker compose exec backend bash scripts/tests-start.sh

The /app/backend/scripts/tests-start.sh script calls pytest after making sure that the rest of the stack is running. If you need to pass extra arguments to pytest, you can pass them to that command and they will be forwarded.

For example, to stop on first error:

bash
docker compose exec backend bash scripts/tests-start.sh -x

Test Coverage

When the tests run, they generate htmlcov/index.html. Open it in your browser to inspect the test coverage.

Migrations

Make sure you create a revision of your models and upgrade the database with that revision every time you change them. From the backend directory, use uv to run Alembic against the PostgreSQL container:

  • Alembic is already configured to import your SQLModel models from ./backend/app/models.py.

  • After changing a model (for example, adding a column), create a revision:

console
$ uv run alembic revision --autogenerate -m "Add column last_name to User model"
  • Commit to the git repository the files generated in the alembic directory.

  • After creating the revision, run the migration in the database (this is what will actually change the database):

console
$ uv run alembic upgrade head

If you don't want to use migrations at all, uncomment the lines in the file at ./backend/app/core/db.py that end in:

python
SQLModel.metadata.create_all(engine)

and comment the line in the file scripts/prestart.sh that contains:

console
$ alembic upgrade head

If you don't want to start with the default models and want to remove them / modify them, from the beginning, without having any previous revision, you can remove the revision files (.py Python files) under ./backend/app/alembic/versions/. And then create a first migration as described above.

Email Templates

The email templates are written with React Email in ./packages/react-email/. The emails directory holds one component per email and the ui directory holds the shared components (layout, heading, button, link, callout).

The rendered HTML in ./backend/app/email-templates/ is generated from those components. It is what the application sends and should not be edited by hand.

To preview the emails while editing them, start the dev server from the root of the project:

console
$ bun run email:dev

Values coming from the backend are declared as Jinja placeholders in the component props, for example username = "{{ username }}". The context for each email is built in generate_*_email() in ./backend/app/utils.py, so a new placeholder needs to be added there too.

Once you are done, regenerate the templates used by the application:

console
$ bun run email:export

File: frontend/README.md

FastAPI Project - Frontend

The frontend is built with Vite, React, TypeScript, TanStack Query, TanStack Router, Tailwind CSS, and shadcn/ui.

Requirements

Quick Start

From the project root, install the dependencies and start the frontend development server:

bash
bun install
bun run dev

Then open http://localhost:5173/ in your browser.

Run uv run bash scripts/prestart.sh and uv run fastapi dev from the backend directory, with PostgreSQL running in Docker Compose. See ../development.md for the complete setup.

To serve the frontend with FastAPI, run bun run build from the frontend directory and open http://localhost:8000.

Check frontend/package.json to see the other available commands.

Removing the Frontend

If you are developing an API-only app and want to remove the frontend, you can do it easily:

  • Remove the ./frontend directory.

  • In the backend/app/main.py file, remove the app.frontend() call.

  • In the backend/Dockerfile file, remove the frontend build stage and the COPY --from=frontend-build instruction.

  • In the compose.override.yml file, remove the playwright service.

  • In the .github/workflows/deploy.yml file, remove the Set up Bun, Install frontend dependencies, and Build frontend steps.

  • In the .fastapicloudignore file, remove the !backend/app/frontend/ entry.

Done, you now have an API-only app. ๐Ÿค“

Generate Client

Automatically

  • From the project root, run the script:
bash
bash ./scripts/generate-client.sh
  • Commit the changes.

Manually

  • Make sure the backend is running.

  • Download the OpenAPI JSON file from http://localhost:8000/api/v1/openapi.json and copy it to a new file openapi.json at the root of the frontend directory.

  • To generate the frontend client, run:

bash
bun run generate-client
  • Commit the changes.

Regenerate the client whenever backend changes affect the OpenAPI schema.

Using a Remote API

By default, the built frontend uses the same origin as the FastAPI app. If you want to use a remote API while running the Vite development server, you can set the environment variable VITE_API_URL to the URL of the remote API. For example, you can set it in the frontend/.env file:

env
VITE_API_URL=https://my-domain.example.com

Then, when you run the frontend, it will use that URL as the base URL for the API.

Code Structure

The frontend code is structured as follows:

  • frontend/src - The main frontend code.
  • frontend/public - Static assets.
  • frontend/src/client - The generated OpenAPI client.
  • frontend/src/components - The components of the frontend, including the shadcn/ui components in frontend/src/components/ui.
  • frontend/src/hooks - Custom hooks.
  • frontend/src/lib - Shared frontend utilities.
  • frontend/src/routes - The frontend routes and pages.

End-to-End Testing with Playwright

The frontend includes initial end-to-end tests using Playwright. To run the tests, you need to have the Docker Compose stack running. Start the stack with the following command:

bash
docker compose run --rm backend bash scripts/prestart.sh
docker compose up -d --wait backend

Then, you can run the tests with the following command:

bash
bunx playwright test

You can also run your tests in UI mode to see the browser and interact with it running:

bash
bunx playwright test --ui

To stop and remove the Docker Compose stack and clean the data created in tests, use the following command:

bash
docker compose down -v

To update the tests, navigate to the tests directory and modify the existing test files or add new ones as needed.

For more information on writing and running Playwright tests, refer to the official Playwright documentation.