FastAPI Basics
We started with uv init which created a minimal project structure. For our web application we want something more: a release_tracker package installed into the virtual environment so tools like fastapi dev, pytest, and deployment systems can resolve our app through a dotted import path (release_tracker.main:app) instead of file paths.
Setting Up the Project
Create the Project
From the parent of your current project directory, run:
cd ..
uv init --package --python "==3.14.*" release_tracker
cd release_tracker
code .
Info
code . opens VS Code on the new project directory. Use the fresh window for the rest of the course so the editor's workspace root matches the project root.
The --package flag tells uv to scaffold this as an installable Python package. You'll get:
src/release_tracker/with an__init__.py(the source directory)pyproject.toml(now including a[build-system]block)README.mdand.python-version- a git repository initialized with a
.gitignore
Note
Using the --python "==3.14.*" flag pins the project to Python 3.14. At the time of this course, psycopg[binary] (the PostgreSQL driver we'll add later) doesn't support Python 3.15 or later yet. Keep an eye on the psycopg news page for the latest supported version, and bump your Python version.
Clean Up the Scaffolded Files
uv init --package assumes you're building a CLI tool, so it adds a [project.scripts] entry to pyproject.toml and a placeholder main() function in src/release_tracker/__init__.py. We're building a web app, not a CLI, so we'll clear both out.
Open pyproject.toml and delete this block:
[project.scripts]
release-tracker = "release_tracker:main"
Then empty out the __init__.py:
rm src/release_tracker/__init__.py
touch src/release_tracker/__init__.py
The empty __init__.py still marks release_tracker as a Python package, so once we add main.py we can write from release_tracker.main import app.
Add the Ruff Config
Since this a new project directory, add a ruff.toml in the project root so the extension picks up our formatting and lint rules:
line-length = 80
extend-exclude = ["alembic/versions"]
[lint]
select = ["E", "F", "I"]
Install FastAPI
Add FastAPI as a dependency:
uv add 'fastapi[standard]>=0.115.0'
The [standard] extra pulls in the optional packages we'll want for development, including the Uvicorn server, the fastapi CLI, and httpx (which we'll use later for testing).
Write Your First FastAPI App
Create src/release_tracker/main.py and add the following code:
from fastapi import FastAPI
app = FastAPI(title="Release Tracker API")
@app.get("/projects")
def list_projects() -> list[dict]:
return [{"id": 1, "name": "Example"}]
Breaking It Down
-
app = FastAPI(...):This creates the core application instance. You'll use this
appobject to register routes, middleware, and event handlers. -
@app.get(...):This is a decorator. It tells FastAPI that the function immediately below it is in charge of handling HTTP
GETrequests that go to that specific URL path. -
Type Hints:
Notice
-> dict[str, str]. FastAPI heavily relies on your type hints to understand what you are returning. -
Returning Dictionaries:
FastAPI automatically converts Python dictionaries into valid JSON responses.
Run the Server
To run our application, we need an ASGI (Asynchronous Server Gateway Interface) server. FastAPI is just a web framework. It doesn't actually bind to a port and listen for network traffic on its own.
Fortunately, fastapi[standard] comes with a powerful CLI and bundles a server called Uvicorn for us!
Run the following command in your terminal:
uv run fastapi dev
uv run: Ensures we are executing the command using the virtual environment managed byuv.fastapi dev: Starts the FastAPI development server, which automatically reloads whenever you save a change to a Python file.
How fastapi dev finds the app
fastapi dev with no arguments works because pyproject.toml includes a [tool.fastapi] block pointing at the application:
[tool.fastapi]
entrypoint = "release_tracker.main:app"
If you haven't configured an entrypoint, pass the path to the module instead:
uv run fastapi dev src/release_tracker/main.py
If you navigate to http://127.0.0.1:8000/projects in your browser, you should see the JSON response returned by your list_projects function!
Understanding pyproject.toml
The pyproject.toml file uv has been managing for us is the modern standard (defined in PEP 621) for configuring Python projects, replacing older files you might have seen in legacy codebases like setup.py, setup.cfg, or requirements.txt.
After the commands above, your pyproject.toml should look like this:
[project]
name = "release-tracker"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
{ name = "Your Name", email = "you@example.com" }
]
requires-python = "==3.14.*"
dependencies = [
"fastapi[standard]>=0.115.0",
]
[build-system]
requires = ["uv_build>=0.11.8,<0.12.0"]
build-backend = "uv_build"
[tool.uv.build-backend]
module-name = "release_tracker"
module-root = "src"
[tool.fastapi]
entrypoint = "release_tracker.main:app"
The description field is still the placeholder text uv init left behind. Update it to something meaningful for this project, like "A release tracking application to track Projects and Tasks".
Key Sections
-
[project]:This block defines the metadata for your application (name, version, supported Python versions).
-
dependencies:This is where
uvrecords the packages your application needs to run. By declaringfastapi[standard]here, any developer who clones your repository can simply runuv syncto install exactly what they need. -
[build-system]:This tells
uvhow to install your project as a package, sorelease_trackeris importable from anywhere in your virtual environment. -
[tool.*]:Various Python tools look for their configuration under
[tool.<name>]blocks in this file. Two are already in play:[tool.uv.build-backend]tellsuvwhere the package source lives, and[tool.fastapi]is the entrypoint thefastapi devcommand.
Note
Don't edit pyproject.toml to add packages, but you may need to edit it directly to add configuration settings.
Why the src/ Layout
Info
We create code under src/release_tracker to keep source code separate from configuration, tests, and scripts.
Simplifying the FastAPI Command
Typing out src/release_tracker/main.py every time you want to start the server gets tedious.
We can configure the fastapi CLI to know where our application lives. Add this block to pyproject.toml:
[tool.fastapi]
entrypoint = "release_tracker.main:app"
Stop your server (Ctrl+C) and start it again using the shorthand command:
uv run fastapi dev
The CLI reads the entrypoint from your configuration file and starts the server automatically. For the rest of the course, you can use this shorthand command.
After this edit, your pyproject.toml should look like this:
[project]
name = "release-tracker"
version = "0.1.0"
description = "A release tracking application to track Projects and Tasks"
readme = "README.md"
authors = [
{ name = "Your Name", email = "you@example.com" }
]
requires-python = "==3.14.*"
dependencies = [
"fastapi[standard]>=0.115.0",
]
[build-system]
requires = ["uv_build>=0.11.8,<0.12.0"]
build-backend = "uv_build"
[tool.fastapi]
entrypoint = "release_tracker.main:app"