Best practices for building FastAPI-based applications. Based on industry-standard FastAPI patterns and our own work.
Copy copilot-instructions.md into your repo at .github/copilot-instructions.md. It consolidates the most important rules from this guide (and the shared standards) into a single concise file that GitHub Copilot reads automatically.
| File | Topic |
|---|---|
| 01-project-structure.md | Directory layout, packaging, and imports |
| 02-app-configuration.md | FastAPI app setup, middleware, lifespan |
| 03-routes-and-schemas.md | Routers, dependency injection, Pydantic models |
| 04-configuration-management.md | Environment variables, settings, secrets |
| 05-error-handling.md | Exception hierarchy, global handlers, error responses |
| 06-authentication.md | API keys, Bearer tokens, multi-tenant auth |
| 07-testing.md | Test pyramid, fixtures, mocking, CI |
| 08-docker.md | FastAPI Dockerfile, ASGI entrypoint (→ shared/docker) |
| 09-ci-cd.md | Docker deploy to Azure (→ shared/ci-cd) |
| 10-dependencies.md | FastAPI-specific deps (→ shared/dependencies) |
| 11-logging-observability.md | ASGI middleware logging (→ shared/logging) |
| 12-code-quality.md | FastAPI type patterns (→ shared/code-quality) |
FastAPI-specific terms used throughout these guides. For shared terms (uv, Ruff, Gunicorn, Lockfile, etc.) see the shared glossary.
| Term | Definition |
|---|---|
| Application factory | A function (conventionally create_app()) that constructs and returns a configured FastAPI instance. Enables injecting different configurations for testing, development, and production without relying on global state. See 02-app-configuration.md. |
| ASGI (Asynchronous Server Gateway Interface) | The Python standard for async web servers and applications. FastAPI is an ASGI application; Uvicorn is an ASGI server. The async counterpart of WSGI. See 08-docker.md. |
Dependency injection (Depends) |
FastAPI's mechanism for declaring that a route handler needs something (auth, database, settings, etc.) provided to it. FastAPI resolves the dependency tree automatically, enabling testability and separation of concerns. See 03-routes-and-schemas.md. |
| Lifespan | An asynccontextmanager passed to FastAPI(lifespan=...) that defines startup logic (before yield) and shutdown logic (after yield). Replaces the deprecated @app.on_event("startup") pattern. See 02-app-configuration.md. |
| Middleware | Code that wraps every request/response cycle. In FastAPI/Starlette, middleware can be raw ASGI classes or BaseHTTPMiddleware subclasses. Used for logging, request IDs, CORS, etc. See 02-app-configuration.md. |
| Pydantic model / schema | A class inheriting from pydantic.BaseModel used to declare, validate, and serialize data. In FastAPI, request bodies and response shapes are defined as Pydantic models, which also drive the auto-generated OpenAPI docs. See 03-routes-and-schemas.md. |
pydantic-settings (BaseSettings) |
A Pydantic extension that reads configuration from environment variables (and .env files) with type validation and SecretStr support. See 04-configuration-management.md. |
Router (APIRouter) |
A FastAPI object that groups related endpoints, similar to Flask's Blueprint. Routers are included in the app with app.include_router(...) and support tags and prefixes for OpenAPI organization. See 03-routes-and-schemas.md. |
SecretStr |
A Pydantic type that masks the value in repr() / logging output ('**********'). Prevents accidental exposure of API keys and passwords. See 04-configuration-management.md. |
| Uvicorn | A high-performance ASGI server that runs FastAPI apps. Used directly in development (uvicorn --reload) and behind Gunicorn workers in production. See 08-docker.md. |
| Gunicorn + UvicornWorker | The production deployment pattern: Gunicorn manages multiple Uvicorn worker processes for concurrency and process resilience. See 08-docker.md. |
dependency_overrides |
A dict on the FastAPI app that lets you swap out real dependencies for fakes/mocks during testing — without monkeypatching. See 07-testing.md. |
| Domain model vs API schema | Domain models represent internal business logic (pure Python, no HTTP concepts). API schemas represent the external HTTP contract (request/response shapes). Keeping them separate allows the API to evolve independently of internals. See 01-project-structure.md. |
| Adapter | A module that wraps an external system (LLM provider, database, third-party API) behind an interface defined in domain/ports.py. Adapters are the outermost layer and can be swapped for fakes in testing. See 01-project-structure.md. |
| Hexagonal architecture (ports & adapters) | The architectural style underpinning this layout: a pure domain/ core surrounded by adapters/ that plug into it, with all dependencies pointing inward toward the domain (Dependency Inversion). Yields testability, replaceable infrastructure, and a framework-free core. See 01-project-structure.md. |
| Port | A Protocol/ABC interface declared in domain/ports.py, phrased in domain terms, describing something the core needs from the outside world (a store, an LLM, a queue). Services depend on ports; adapters implement them. See 01-project-structure.md. |
| Composition root | The single outermost place — typically create_app() / lifespan in api/app.py — where concrete adapters are constructed and wired into the ports that services expect. The only layer allowed to know about everything. See 02-app-configuration.md. |