# Full Stack FastAPI Template — User Guide

The **Full Stack FastAPI Template** is a production-ready starter kit for building
web applications with a Python backend and a React frontend. You clone (or generate)
it once, and you get a complete, working application: a JWT-authenticated REST API,
a database with migrations, a single-page admin dashboard, email-based password
recovery, automated tests, and a Docker Compose setup that runs everything together.

Rather than wiring FastAPI, SQLModel, PostgreSQL, React, and Traefik together
yourself, you start from a stack that is already integrated, tested in CI, and ready
to customize into your own product.

> [!NOTE]
> This is a **template**, not a library you install. The goal is to give you a
> running codebase to build *on top of* — you own and edit every file after you
> generate your project.

---

## 1. Quick Start

Get the full application running locally in a few minutes. You need [Docker](https://www.docker.com/)
(Docker Engine with Compose) installed.

```bash
# 1. Get the code (use it as-is for now)
git clone https://github.com/fastapi/full-stack-fastapi-template.git my-app
cd my-app

# 2. Start the whole stack (backend, frontend, database, proxy, mail catcher)
docker compose watch
```

The first start takes a minute while the backend waits for the database and seeds
the first admin user. Once it is up, open these URLs in your browser:

| Service | URL | What it is |
|---|---|---|
| Frontend dashboard | <http://localhost:5173> | The React single-page app |
| Backend API | <http://localhost:8000> | The FastAPI JSON API |
| Interactive API docs (Swagger UI) | <http://localhost:8000/docs> | Try every endpoint in the browser |
| Alternative API docs (ReDoc) | <http://localhost:8000/redoc> | Reference-style API docs |
| Adminer (database UI) | <http://localhost:8080> | Browse and edit the database |
| Traefik dashboard | <http://localhost:8090> | See how the proxy routes traffic |
| Mailcatcher | <http://localhost:1080> | Read emails the app "sends" locally |

Log in to the dashboard with the default superuser credentials that ship in the
`.env` file:

```text
Email:    [email removed]
Password: changethis
```

> [!CAUTION]
> The default `.env` ships with placeholder secrets set to `changethis`
> (`SECRET_KEY`, `POSTGRES_PASSWORD`, `FIRST_SUPERUSER_PASSWORD`). They are fine for
> a quick local spin, but you **must** change them before deploying anywhere. See
> [Generating secure secrets](#43-generate-secure-secrets).

> [!TIP]
> `docker compose watch` keeps your running containers in sync with your source
> code — when you edit a backend or frontend file, the change is synced into the
> container automatically. To follow logs while it runs, open a second terminal and
> run `docker compose logs` (or `docker compose logs backend` for one service).

---

## 2. Starting Your Own Project

You have two ways to turn this template into your own project: **clone it directly**
(simplest) or **generate it with Copier** (customizes names and secrets for you as it
copies). Both leave you with a normal Git repository you fully own.

=== "Clone or fork (simplest)"

    You can just fork or clone the repository and use it as-is. To start a private
    project from it (GitHub does not let you make a fork private), clone it under your
    own name and re-point the remote:

    ```bash
    # Clone into a directory named for your project
    git clone git@github.com:fastapi/full-stack-fastapi-template.git my-full-stack
    cd my-full-stack

    # Point "origin" at your own (new, empty) repository
    git remote set-url origin git@github.com:your-org/my-full-stack.git

    # Keep the template as "upstream" so you can pull future updates
    git remote add upstream git@github.com:fastapi/full-stack-fastapi-template.git

    # Push to your repository
    git push -u origin master
    ```

=== "Generate with Copier (customized)"

    [Copier](https://copier.readthedocs.io) copies all the files, asks you a few
    configuration questions, and fills your `.env` files with your answers (including
    auto-generating secure secrets).

    ```bash
    # Install copier (pipx recommended)
    pipx install copier

    # Generate a new project into ./my-awesome-project
    copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust
    ```

    If you have `pipx` you can skip the install and run it directly:

    ```bash
    pipx run copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust
    ```

    > [!IMPORTANT]
    > The `--trust` flag is **required**. The template runs a post-generation script
    > (`.copier/update_dotenv.py`) that writes your answers into the `.env` files;
    > Copier will not execute it without `--trust`.

### 2.1 Copier input variables

When you generate with Copier, you are asked for the following. You can change any of
them later by editing the `.env` file, so don't overthink them now.

| Variable | Default | Purpose |
|---|---|---|
| `project_name` | `FastAPI Project` | Project name shown to API users (in API docs and emails) |
| `stack_name` | `fastapi-project` | Name used for Docker Compose labels — no spaces or periods |
| `secret_key` | `changethis` | Secret key used to sign tokens — generate a real one |
| `first_superuser` | `[email removed]` | Email of the first admin user |
| `first_superuser_password` | `changethis` | Password of the first admin user — change it |
| `smtp_host` | *(empty)* | SMTP server host for sending email (optional, set later) |
| `smtp_user` | *(empty)* | SMTP username (optional) |
| `smtp_password` | *(empty)* | SMTP password (optional) |
| `emails_from_email` | `[email removed]` | "From" address for outgoing email |
| `postgres_password` | `changethis` | PostgreSQL password — generate a real one |
| `sentry_dsn` | *(empty)* | Sentry DSN for error tracking (optional) |

### 2.2 Pulling updates from the template later

Because you added the template as `upstream`, you can pull its later improvements into
your project:

```bash
# Download the latest template changes without committing them
git pull --no-commit upstream master

# Resolve any conflicts in your editor, then finish the merge
git merge --continue
```

> [!TIP]
> `--no-commit` lets you review everything the template changed before it lands in
> your history — useful because you will have edited many of the same files.

---

## 3. What You Get — The Application Tour

Once you log in, the template gives you a working dashboard built around two example
resources: **users** (people who can log in) and **items** (a simple owned resource you
replace with your own data model). Everything here is real, working code you can
study and adapt.

### 3.1 Authentication

The app ships with a complete authentication flow, all backed by JWT access tokens:

- **Log in** (`/login`) — email + password, returns an access token stored in the browser.
- **Sign up** (`/signup`) — self-service registration for new users.
- **Forgot password** (`/recover-password`) — enter your email to receive a reset link.
- **Reset password** (`/reset-password`) — set a new password using the emailed token.

> [!NOTE]
> Password recovery emails are only **sent** when SMTP is configured. During local
> development they are captured by Mailcatcher instead — open <http://localhost:1080>
> to read them. See [Email in development](#54-reading-emails-in-development).

### 3.2 The dashboard

After logging in you land on the dashboard, which uses a collapsible sidebar for
navigation. The pages available are:

| Page | Route | What you can do |
|---|---|---|
| Dashboard | `/` | Landing page greeting the logged-in user |
| Items | `/items` | Create, view, edit, and delete your items in a paginated table |
| Admin | `/admin` | (Superusers) Manage all users — add, edit, delete |
| User Settings | `/settings` | Update your profile, change password, change appearance, delete account |

### 3.3 Managing items

The **Items** page is the template's example of a full create-read-update-delete (CRUD)
feature, wired end to end from the database to the UI:

- Click **Add Item** to create one (title required, description optional).
- Each item appears in a sortable, paginated table.
- Use the per-row actions menu to **edit** or **delete** an item.
- Regular users see only their own items; superusers see everyone's.

This is the feature you will most likely copy and rename when you build your own
resource. See the Admin Guide for how the item model, API routes, and frontend pages
fit together.

### 3.4 Managing users (admin)

Superusers get an **Admin** page to manage every account:

- **Add User** — create a user with an email, name, password, and optional superuser/active flags.
- **Edit User** — change a user's details or reset their password.
- **Delete User** — remove a user (and, via cascade, their items).

> [!NOTE]
> The **first** superuser is created automatically from `FIRST_SUPERUSER` /
> `FIRST_SUPERUSER_PASSWORD` in your `.env` the first time the stack starts. From
> there, that superuser can create other users through the Admin page or the API.

### 3.5 User settings

Every logged-in user can manage their own account from **Settings**:

- **My profile** — update full name and email.
- **Password** — change your password (requires your current password).
- **Appearance** — switch between light and dark mode (the app ships with **dark mode by default**).
- **Danger zone** — permanently delete your own account.

### 3.6 Dark mode

The interface supports light and dark themes out of the box, defaulting to dark. Your
choice is remembered in the browser between visits.

---

## 4. Configuration

All configuration lives in a single **`.env`** file at the root of the project. The
backend, frontend build, database, and proxy all read from it. After changing any
value, restart the stack with `docker compose watch`.

### 4.1 The essentials

These are the values you are most likely to set when starting out:

| Variable | Default | What it does |
|---|---|---|
| `PROJECT_NAME` | `Full Stack FastAPI Project` | Name shown in API docs and emails |
| `STACK_NAME` | `full-stack-fastapi-project` | Docker Compose project/label name (no spaces/dots) |
| `DOMAIN` | `localhost` | Base domain; becomes your real domain in production |
| `FRONTEND_HOST` | `http://localhost:5173` | Where the frontend lives (used in email links) |
| `ENVIRONMENT` | `local` | One of `local`, `staging`, `production` |
| `FIRST_SUPERUSER` | `[email removed]` | Email of the auto-created admin |
| `FIRST_SUPERUSER_PASSWORD` | `changethis` | Password of the auto-created admin |

### 4.2 Database, email, and secrets

| Variable | Default | What it does |
|---|---|---|
| `POSTGRES_SERVER` | `localhost` | Database host (`db` inside Docker Compose) |
| `POSTGRES_PORT` | `5432` | Database port |
| `POSTGRES_DB` | `app` | Database name |
| `POSTGRES_USER` | `postgres` | Database user |
| `POSTGRES_PASSWORD` | `changethis` | Database password — **change this** |
| `SECRET_KEY` | `changethis` | Signs login tokens — **change this** |
| `BACKEND_CORS_ORIGINS` | local hosts | Comma-separated list of browser origins allowed to call the API |
| `SMTP_HOST` | *(empty)* | SMTP server for sending email (leave empty to disable email) |
| `SMTP_USER` / `SMTP_PASSWORD` | *(empty)* | SMTP credentials |
| `SMTP_PORT` | `587` | SMTP port |
| `SMTP_TLS` / `SMTP_SSL` | `True` / `False` | SMTP encryption mode |
| `EMAILS_FROM_EMAIL` | `[email removed]` | "From" address for outgoing email |
| `SENTRY_DSN` | *(empty)* | Sentry error-tracking DSN (optional) |

> [!TIP]
> Email features (password recovery, new-account notifications) turn on
> automatically once **both** `SMTP_HOST` and `EMAILS_FROM_EMAIL` are set. Until then,
> the API simply skips sending — nothing breaks.

For the complete list of every setting, including advanced backend-only options like
token lifetimes, see the **Admin Guide → Configuration Reference**.

### 4.3 Generate secure secrets

Three values ship as `changethis` and must be replaced before any real deployment:
`SECRET_KEY`, `POSTGRES_PASSWORD`, and `FIRST_SUPERUSER_PASSWORD`. Generate a strong
random value for each:

```bash
python -c "import secrets; print(secrets.token_urlsafe(32))"
```

```text
Xy7d9F2kQ1mN8pZ3rT6vW0bJ4hL5sG... (example — yours will differ)
```

Run it once per secret and paste the result into `.env`.

> [!WARNING]
> If you set `ENVIRONMENT` to `staging` or `production` while any of these three is
> still `changethis`, the backend **refuses to start** and raises an error. This is a
> deliberate safety check, not a bug.

---

## 5. Developing on the Template

This is starter code — you are meant to edit it. The stack is designed so you can run
each part either inside Docker or directly on your machine, whichever is faster for the
change you are making.

### 5.1 Run a service locally instead of in Docker

Each service uses the same port whether it runs in Docker or locally, so you can stop
the container and start a local dev server in its place with no other changes.

For the **frontend** (live reload, fastest for UI work):

```bash
docker compose stop frontend
cd frontend
bun install
bun run dev
```

For the **backend** (live reload via FastAPI):

```bash
docker compose stop backend
cd backend
uv sync
source .venv/bin/activate
fastapi dev app/main.py
```

> [!NOTE]
> The backend uses [uv](https://docs.astral.sh/uv/) for Python dependencies and the
> frontend uses [Bun](https://bun.sh/) (Node.js also works). Both are the recommended
> tools but only needed if you run a service outside Docker.

### 5.2 Where the code lives

| You want to change... | Edit... |
|---|---|
| Data models / database tables | `backend/app/models.py` |
| API endpoints | `backend/app/api/routes/` |
| Database read/write helpers | `backend/app/crud.py` |
| Backend settings | `backend/app/core/config.py` (values in `.env`) |
| Frontend pages | `frontend/src/routes/` |
| Reusable UI components | `frontend/src/components/` |
| Frontend hooks | `frontend/src/hooks/` |

### 5.3 Keeping the frontend API client in sync

The frontend talks to the backend through an **automatically generated** TypeScript
client (in `frontend/src/client/`). Whenever you change the backend API, regenerate the
client so the frontend stays type-safe:

```bash
# From the project root, with the backend running
bash ./scripts/generate-client.sh
```

Then commit the regenerated files. This means you never hand-write API calls — adding a
backend endpoint and regenerating gives you a ready-to-use typed function on the frontend.

> [!TIP]
> Forgetting to regenerate after a backend change is the most common source of
> frontend type errors. If TypeScript complains about a missing service or field, run
> the generator first.

### 5.4 Reading emails in development

When running with Docker Compose locally, the backend is automatically pointed at
**Mailcatcher** instead of a real mail server. Any email the app "sends" (password
recovery, new-account notices) is captured and shown at <http://localhost:1080>. No
real email leaves your machine.

### 5.5 Running the tests

The backend ships with a Pytest suite and the frontend with Playwright end-to-end tests.

Backend tests:

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

Frontend end-to-end tests (stack must be running):

```bash
cd frontend
bunx playwright test
```

```bash
# Watch the tests run in an interactive UI
bunx playwright test --ui
```

---

## 6. Building an API-Only App

If you only need the backend (no dashboard), you can remove the frontend cleanly:

- [ ] Delete the `./frontend` directory.
- [ ] Remove the `frontend` service from `compose.yml`.
- [ ] Remove the `frontend` and `playwright` services from `compose.override.yml`.

That's it — you now have an API-only application. The `FRONTEND` environment variables
can be left in place; they simply have no effect.

---

## 7. Troubleshooting

### Error: `The value of SECRET_KEY is "changethis"...`

**Cause:** You set `ENVIRONMENT` to `staging` or `production` while `SECRET_KEY`,
`POSTGRES_PASSWORD`, or `FIRST_SUPERUSER_PASSWORD` is still the placeholder `changethis`.
**Solution:** Generate real values (see [4.3](#43-generate-secure-secrets)) and put them
in `.env`. **Prevention:** Always change the three secrets before changing `ENVIRONMENT`.

### Error: `Incorrect email or password`

**Cause:** The credentials sent to `/login/access-token` don't match an active user.
**Solution:** Use the `FIRST_SUPERUSER` / `FIRST_SUPERUSER_PASSWORD` from your `.env`,
or sign up a new account. **Prevention:** Remember email login is case- and
whitespace-sensitive.

### The stack starts but the dashboard can't reach the API

**Cause:** Your browser's origin isn't in `BACKEND_CORS_ORIGINS`, so the API rejects the
request. **Solution:** Add your frontend URL to `BACKEND_CORS_ORIGINS` in `.env` (comma
separated) and restart. **Prevention:** Keep this list in sync whenever you change
`DOMAIN` or `FRONTEND_HOST`.

### The backend takes a long time to start (or restarts repeatedly)

**Cause:** The backend waits for PostgreSQL to be ready before it starts (up to five
minutes), retrying once per second. **Solution:** Watch `docker compose logs db` and
`docker compose logs backend`; a healthy database resolves it. **Prevention:** Make sure
your `POSTGRES_*` values are consistent across `.env`.

### Frontend type errors after a backend change

**Cause:** The generated API client is stale. **Solution:** Run
`bash ./scripts/generate-client.sh` and commit the result. **Prevention:** Regenerate
the client every time the backend API changes.

### Password recovery "works" but no email arrives

**Cause:** Email is only sent when `SMTP_HOST` **and** `EMAILS_FROM_EMAIL` are both set;
locally, email goes to Mailcatcher. **Solution:** Check <http://localhost:1080> in
development, or configure SMTP for production. **Prevention:** Confirm both SMTP values
are present before expecting real delivery.

### `docker compose watch` isn't picking up my changes

**Cause:** `watch` syncs source into the container, but some changes (like new
dependencies) require a rebuild. **Solution:** Stop and re-run `docker compose watch`;
for dependency changes the backend image rebuilds automatically. **Prevention:** Restart
the stack after editing `pyproject.toml` or `package.json`.

---

## 8. Frequently Asked Questions

**Q: Do I install this from npm or pip?**
No. It is a project template you clone or generate with Copier, then own and edit. There
is no package to install.

**Q: Which database does it use?**
PostgreSQL. The connection is assembled from the `POSTGRES_*` variables in `.env`.

**Q: How long do login sessions last?**
Access tokens are valid for 8 days by default. This is configurable in the backend
(see the Admin Guide).

**Q: Can I use a different frontend or no frontend at all?**
Yes. The backend is fully independent; see [Building an API-Only App](#6-building-an-api-only-app).
You can also point the frontend at a remote backend by setting `VITE_API_URL`.

**Q: How do I add my own data model (instead of "items")?**
Add a model in `backend/app/models.py`, create API routes under
`backend/app/api/routes/`, create an Alembic migration, then regenerate the frontend
client and build a page under `frontend/src/routes/`. The existing "items" feature is a
complete worked example to copy.

**Q: How do I change the database schema?**
Edit `backend/app/models.py`, then create and apply an Alembic migration. The Admin
Guide covers the exact commands.

**Q: Where do the API docs come from?**
FastAPI generates them automatically from your code. Visit `/docs` (Swagger UI) or
`/redoc` while the backend is running.

**Q: Is it ready for production?**
The template is built for it — it includes Traefik with automatic HTTPS, multi-stage
Docker builds, and GitHub Actions CI/CD. You still must set real secrets and a domain.
See the Admin Guide → Deployment.

**Q: How do I get future improvements from the template?**
Add it as a Git `upstream` remote and `git pull --no-commit upstream master` (see
[2.2](#22-pulling-updates-from-the-template-later)).

**Q: What's the difference between a regular user and a superuser?**
Superusers can manage all users and see all items; regular users can only manage their
own account and their own items.

---

_Generated June 2026 from fastapi/full-stack-fastapi-template at 38302d7. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
