Skip to main content

Two apps, one project

A full-stack app is two separate applications that talk to each other: a React frontend (what users see) and a FastAPI backend (your API and database). They run independently, communicate over HTTP, and live in separate folders.
This lesson uses a simplified JS-first structure to teach the pattern clearly. The companion repo uses a more production-style layout: backend/main.py + backend/routers/users.py + backend/models.py + backend/database.py, a TypeScript web frontend (.tsx/.ts), and a mobile/ Expo app that uses the same API.
This is the standard structure. You’ll see it in almost every full-stack project.

The backend (FastAPI)

Your FastAPI backend is a Python project you already know how to build. Here’s the minimum:
In the companion repo, the backend uses uv with pyproject.toml, so the command is uv run fastapi dev main.py instead of uvicorn main:app --reload.
Your API is now running at http://localhost:8000. You can test it at http://localhost:8000/docs (FastAPI’s built-in Swagger UI).

The frontend (React)

Your React frontend is a Vite project that fetches data from the backend:
React runs at http://localhost:5173. It makes fetch() calls to http://localhost:8000/api/... to get and send data.
The frontend and backend run on different ports (5173 and 8000). They’re completely separate applications. The frontend doesn’t know or care that the backend is Python — it just makes HTTP requests and gets JSON back.

How they communicate

The frontend uses fetch() to make HTTP requests (GET, POST, PUT, DELETE). The backend processes the request and returns JSON. The frontend updates its state with the response and re-renders the UI. This is the same architecture used by every major web application — Gmail, Twitter, Spotify. The only difference is scale.

Running both together

During development, you need two terminal windows:
Keep both terminals visible. When you see an error in the browser, check both terminals — the bug could be on either side. FastAPI’s terminal shows Python errors. Vite’s terminal shows JavaScript build errors.

.gitignore

Make sure you don’t commit dependencies or secrets:

What’s next?

Your project is structured. But those hardcoded URLs (http://localhost:8000) won’t work in production. Let’s fix that with environment variables.

Environment variables

Manage configuration and secrets across development and production