# FastAPI

Typed Python APIs alongside Python integrations, data or AI libraries.

FastAPI · Pydantic · SQLAlchemy · Alembic

[Complete guide (Markdown)](/stacks/python-fastapi/guide.md) · [Structured record (JSON)](/stacks/python-fastapi/record.json)

Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. [Check scope](/research-freshness.json). Dependency combinations and setup need project-specific qualification.

## Use cases

- Typed JSON APIs

- Integration services

- HTTP endpoints for model or worker products

## Choose it when

- API contracts and Python integrations matter more than built-in product/admin UI

- A separate frontend or service boundary already exists

## Consider another path when

- The team mostly needs accounts, admin, forms and CRUD that Django supplies

- Blocking or CPU-intensive jobs would be run inside request event loops

## Working practices

- Validate tokens and permissions in dependencies; Pydantic validation does not establish authorization.

- Keep blocking calls out of async request handling and configure database connection lifetimes.

- Commit and rehearse Alembic migrations. Use isolated databases for integration tests.

- Move durable work to operated workers; an in-process background task cannot guarantee recovery.

## Tools by job

### Packaging and environments: uv + pyproject.toml + committed uv.lock

One project entry point for dependencies, Python selection, execution and reproducible sync.

Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.

- [https://docs.astral.sh/uv/guides/projects/](https://docs.astral.sh/uv/guides/projects/)

### Lint and format: Ruff

Fast lint and formatting feedback with one configuration.

Ruff does not replace static typing, tests, authorization checks or runtime validation.

- [https://docs.astral.sh/ruff/installation/](https://docs.astral.sh/ruff/installation/)

### Static typing: mypy

Explicit checks on application boundaries with a conservative established checker.

Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run.

- [https://mypy.readthedocs.io/en/stable/getting_started.html](https://mypy.readthedocs.io/en/stable/getting_started.html)

- [https://docs.astral.sh/ty/type-checking/](https://docs.astral.sh/ty/type-checking/)

### Testing: pytest + HTTPX / FastAPI TestClient

Test contract failures, auth and integration boundaries.

Run startup/shutdown lifespan when relevant; include PostgreSQL and external-service fault tests.

- [https://docs.pytest.org/en/stable/getting-started.html](https://docs.pytest.org/en/stable/getting-started.html)

- [https://fastapi.tiangolo.com/deployment/docker/](https://fastapi.tiangolo.com/deployment/docker/)

### Database and migrations: PostgreSQL + SQLAlchemy + Psycopg + Alembic

Explicit transactions and versioned relational changes.

Session per thread / AsyncSession per task. Review generated migrations, especially renames and data changes; a passing migration check does not prove production lock safety.

- [https://docs.sqlalchemy.org/en/21/orm/session_basics.html](https://docs.sqlalchemy.org/en/21/orm/session_basics.html)

- [https://alembic.sqlalchemy.org/en/latest/autogenerate.html](https://alembic.sqlalchemy.org/en/latest/autogenerate.html)

### Validation: Pydantic request/response models; strict validation where coercion is unsafe

Typed schemas clarify external contracts and generated documentation.

Coercion is configurable; schema validity is not authorization or business correctness. Avoid returning unrestricted ORM objects.

- [https://pydantic.dev/docs/validation/latest/concepts/strict_mode/](https://pydantic.dev/docs/validation/latest/concepts/strict_mode/)

### Authentication: Existing OIDC provider; validate access tokens and authorization in dependencies

Keep identity lifecycle with its owner while enforcing permissions at the API.

Choose and verify token-validation integration at implementation. FastAPI's JWT tutorial is not a complete identity system; issuer, audience, expiry and permissions need tests.

- [https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/)

- [https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html](https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html)

### Jobs: Separate Celery workers for queued jobs

Separate request latency from heavy or retried work.

BackgroundTasks does not establish durable execution. Make job effects idempotent and set retry/deadline limits.

- [https://fastapi.tiangolo.com/tutorial/background-tasks/](https://fastapi.tiangolo.com/tutorial/background-tasks/)

- [https://docs.celeryq.dev/en/stable/userguide/tasks.html](https://docs.celeryq.dev/en/stable/userguide/tasks.html)

- [https://docs.temporal.io/develop/python](https://docs.temporal.io/develop/python)

### Long-running durable agents: Temporal Python SDK when recovery across restarts is required

Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.

Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.

- [https://docs.temporal.io/develop/python](https://docs.temporal.io/develop/python)

- [https://docs.celeryq.dev/en/stable/userguide/tasks.html](https://docs.celeryq.dev/en/stable/userguide/tasks.html)

### Serving and deployment: FastAPI standard CLI / Uvicorn in a container

Official deployment path with explicit process and container choices.

Build from a supported base rather than deprecated framework images; choose process count to match deployment/memory, and run schema migration once per release.

- [https://fastapi.tiangolo.com/deployment/docker/](https://fastapi.tiangolo.com/deployment/docker/)

- [https://docs.astral.sh/uv/guides/integration/docker/](https://docs.astral.sh/uv/guides/integration/docker/)

- [https://fastapi.tiangolo.com/async/](https://fastapi.tiangolo.com/async/)

### Application logging: Python logging with configured handlers

Shared standard logging captures application and dependency diagnostics

Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.

- [https://docs.python.org/3/library/logging.html](https://docs.python.org/3/library/logging.html)

### Bounded external-call retries: Tenacity only for retryable transient failures

Explicit stop/wait/filter rules support controlled retries

Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.

- [https://tenacity.readthedocs.io/en/latest/](https://tenacity.readthedocs.io/en/latest/)

### Uploads: FastAPI UploadFile

Spooling file interface avoids eagerly materializing all content in application memory

Install python-multipart; enforce request/file limits and authorization, stream to durable storage and clean partial writes. Multipart parsing does not establish file safety.

- [https://fastapi.tiangolo.com/tutorial/request-files/](https://fastapi.tiangolo.com/tutorial/request-files/)

### Realtime transport: FastAPI WebSocket endpoints

Native ASGI endpoint support fits connected API clients

Authorize handshake/messages; bound per-client queues, handle disconnect and share state through an external service for replicas. In-memory tutorial connection lists are not multi-process state.

- [https://fastapi.tiangolo.com/advanced/websockets/](https://fastapi.tiangolo.com/advanced/websockets/)

### Object storage: Boto3 S3 client when durable objects are required

Official SDK supports file transfer to S3

Install boto3 only for S3-backed work; use platform credentials, private keys and bounded transfers. Boto3 is synchronous: keep blocking transfers out of an async event loop; verify alternative provider compatibility.

- [https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html](https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html)

Build with the stack’s strengths

## Architecture and developer workflow.

FastAPI exposes Python type-annotated HTTP operations and dependency boundaries. It supports synchronous and async handlers; the choice depends on whether called libraries support await. Recommendation: keep request models distinct from persistence operations and explicitly select identity, durable jobs, database migrations and distributed messaging instead of assuming the API framework provides an integrated monolith.

Version scope: Current FastAPI online guides fetched 11 October 2026; these pages do not pin an application package release. SQLAlchemy 2.0 documentation, Alembic 1.20.0 documentation and Celery 5.6.3 reviewed. Pin actual Python/FastAPI/Pydantic/Starlette/database-driver versions before implementation. · Reviewed 2026-10-11

### Architecture boundaries

- Use async handlers with awaitable I/O, or normal def handlers for blocking libraries as the guide explains. Recommendation: keep CPU-heavy or durable work behind a deliberate worker boundary; adding async syntax does not change its durability or CPU execution model.

- SQLAlchemy Sessions are mutable transaction state and cannot be shared across concurrent tasks/threads. Recommendation: scope a Session to its operation, keep the engine/pool separate and use reviewed Alembic revisions for schema evolution.

- FastAPI lifespan manages startup/shutdown resources. Multiple worker processes are a deployment choice; recommendation: treat in-memory connections/caches as worker-local and keep one external scheduler and migration owner.

### Tools and feedback

- For a configured application, adapt fastapi run --workers 4 main.py or uvicorn main:app --workers 4 from the deployment guide; replace module and worker count for the actual host/container topology. The example is a recipe, not a capacity recommendation.

- For a configured SQLAlchemy/Alembic application, use alembic revision -m "Add a column", review upgrade/downgrade operations, then alembic upgrade head in a disposable database; alembic current and alembic history show recorded state.

- Use FastAPI TestClient and pytest for HTTP contract tests. Recommendation: add real database/worker tests for transaction and retry boundaries, plus WebSocket tests across the intended multi-process topology.

- Recommendation: initialize shared process resources through the lifespan context and create independent database sessions for concurrent operations. Validate selected sync/async client usage and cleanup on shutdown before rollout.

### Translations to avoid

- Avoid using BackgroundTasks as a durable queue replacement: it executes work associated with the application process, while the guide recommends larger worker tools such as Celery for work that belongs in multiple processes/servers. Recommendation: qualify crash/retry behavior explicitly.

- Avoid copying the tutorial’s in-memory WebSocket connection list into a multi-worker product; the docs explicitly say it works only in one running process.

- Avoid sharing one SQLAlchemy Session among requests/tasks or moving blocking library calls unchanged inside async handlers; the documented concurrency boundaries differ.

- Avoid treating a JWT tutorial as a complete identity migration. Recommendation: retain existing identity authority until issuer, account mapping, validation, expiry and revocation are designed. Starlette SessionMiddleware signs readable cookie contents; signing is not confidentiality.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/async/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/sql-databases/)
[docs.sqlalchemy.org →](https://docs.sqlalchemy.org/en/20/orm/session_basics.html)
[alembic.sqlalchemy.org →](https://alembic.sqlalchemy.org/en/latest/tutorial.html)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/background-tasks/)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/userguide/tasks.html)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/)
[starlette.dev →](https://starlette.dev/middleware/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/websockets/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/events/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/deployment/server-workers/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/testing/)
[redis.io →](https://redis.io/docs/latest/develop/clients/redis-py/)

For an existing application

## Keep the contracts while you change the stack.

These are documented options and proposed checks. Inspect the actual source application before adopting a transition.

Data and schema

### Inspect the source

Inventory schema, primary IDs, SQL value/constraint semantics and existing transaction ownership. The old application may use an ORM with callbacks absent from the target service.

### During coexistence

Recommendation: keep one writer and migration runner; start with read-only target endpoints or a bounded domain operation. Preserve additive schema and qualify ORM/session behavior before transferring writes.

### Target design

SQLAlchemy 2.0 Sessions scoped to operations, with reviewed Alembic upgrade/downgrade revisions and the selected PostgreSQL driver. Recommendation: keep transaction and external delivery boundaries explicit.

### Rollback

Recommendation: restore the old writer while preserving backward-readable schema; use downgrade only for a rehearsed reversible change and reconcile accepted new data.

### Benefits and prerequisites

**Recommendation: explicit sessions and migrations expose the persistence boundary to review.**
Requires: Qualified schema mapping, operation-scoped sessions and one writer owner.
Tradeoffs: FastAPI does not remove ORM/migration choices; deleting data cannot be undone by traffic rollback.

### Checks before transfer

- Create through each allowed writer and read through both runtimes; compare IDs, timestamps/null values and constraint failures.

- Run concurrent requests with separate sessions and fail one transaction; no other request’s changes or Session state may leak.

- Apply a reviewed revision to a disposable restored database and verify both deployed versions still read new writes.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/sql-databases/)
[docs.sqlalchemy.org →](https://docs.sqlalchemy.org/en/20/orm/session_basics.html)
[alembic.sqlalchemy.org →](https://alembic.sqlalchemy.org/en/latest/tutorial.html)

Jobs and schedules

### Inspect the source

Record old task name/class, serialized arguments, broker, retries/acknowledgements, schedule ownership and every backlog state. BackgroundTasks and a broker-backed worker are different execution contracts.

### During coexistence

Recommendation: retain old consumers and isolate new categories behind a versioned task interface. Use configured Celery or another separately qualified persistent system when restart recovery matters; keep one schedule owner and a recoverable domain-to-broker handoff.

### Target design

An explicitly selected durable worker/broker composition with business idempotency. Small best-effort same-process tasks may use BackgroundTasks only when their documented process boundary fits the requirement.

### Rollback

Recommendation: stop new task production, retain consumers for accepted payload versions and reconcile external effects before restoring old routing.

### Benefits and prerequisites

**Recommendation: durable work can move independently of the HTTP service.**
Requires: Selected broker/worker configuration, tested payloads and explicit idempotency/recovery policy.
Tradeoffs: The broker and worker add operated components; returning HTTP success before enqueue acceptance must have a deliberate contract.

### Checks before transfer

- Enqueue while the worker is stopped, restart it and verify the intended completion/failure result.

- Crash after an external effect before acknowledgement and verify retry is safe; test broker outage during a domain write.

- Reconcile delayed/retry/failed/running tasks and verify the old and new schedulers never both produce the category.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/background-tasks/)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/userguide/tasks.html)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html)

Identity and authorization

### Inspect the source

Capture the source identity authority, token/cookie format, issuer/audience rules, account IDs, expiration and revocation. The FastAPI OAuth2/JWT guide is a concrete example, not proof of compatibility with existing sessions.

### During coexistence

Recommendation: retain the existing identity authority through qualified token verification or session exchange. Move resource authorization with the domain operation, and keep cookie scope/CSRF behavior explicit when using browser cookies.

### Target design

Selected OAuth2/token or browser-session implementation with deliberate account mapping and authorization. If using Starlette SessionMiddleware, cookie data is signed and readable; use https_only and appropriate scope settings for the selected deployment.

### Rollback

Recommendation: preserve account mapping and old credential/exchange support without reversing revocations; return routing only when validation remains compatible.

### Benefits and prerequisites

**Recommendation: a shared identity authority can preserve access across service boundaries.**
Requires: Qualified token/session validation and common revocation policy.
Tradeoffs: Bearer expiry and server-side revocation are distinct design choices; readable signed cookies must not contain secrets.

### Checks before transfer

- Accept a valid source credential and reject modified/expired credentials and a valid credential for another tenant’s protected record.

- Logout/revoke and confirm both old/new paths follow the agreed policy, including an existing WebSocket connection.

- Inspect the selected cookie contents and transport flags; no secret should be exposed by a signed-but-readable session.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/)
[starlette.dev →](https://starlette.dev/middleware/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/websockets/)

Realtime transport

### Inspect the source

Capture the old client protocol, message envelope, connection authentication, subscription scopes and recovery requirements. FastAPI provides WebSocket handlers; its in-memory chat example is explicitly single-process.

### During coexistence

Recommendation: retain the old endpoint for old clients, bridge versioned domain events and route a stable user/room cohort including reconnects. Keep fanout in a separately qualified shared system when multiple worker processes must reach the same recipients.

### Target design

FastAPI WebSocket handlers with explicit shared fanout and persisted domain-state/cursor recovery when required. No specific broker/client combination is integration-qualified by this research.

### Rollback

Recommendation: preserve old endpoint/message compatibility through reconnects; return the cohort and reconcile current domain state instead of reissuing effects.

### Benefits and prerequisites

**Recommendation: an API service can take ownership of a realtime boundary incrementally.**
Requires: Matching message/client protocol, subscription authorization and a tested multi-worker fanout implementation.
Tradeoffs: Connection lists remain worker-local; selecting a shared broker does not itself provide catch-up or protocol compatibility.

### Checks before transfer

- Connect clients to different workers, commit one domain event and verify all authorized recipients converge.

- Restart the worker containing a connection, reconnect and recover missed state; test a revoked identity attempting to rejoin.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/websockets/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/deployment/server-workers/)

Caching and shared state

### Inspect the source

List reconstructible values and representation/TTL/invalidation separately from identities, jobs, counters and locks. Multiple application workers have distinct in-memory resource ownership.

### During coexistence

Recommendation: keep the existing shared store for coordination; use versioned keys for new representations. Move only disposable values to local caching when per-worker staleness and rebuilding are explicitly accepted.

### Target design

A selected shared cache accessed with a qualified client such as redis-py, or an explicitly bounded local cache. Recommendation: match sync/async client usage to the handler and manage process resource lifetime deliberately.

### Rollback

Recommendation: restore old key/backend routing and repopulate from domain data; preserve shared coordination ownership throughout.

### Benefits and prerequisites

**Recommendation: cache choices can evolve without transferring domain ownership.**
Requires: Reconstructible values, explicit invalidation and a complete list of shared-store uses.
Tradeoffs: Local values diverge across workers; removing Redis requires separately retiring sessions/queues/coordination, not merely replacing cached reads.

### Checks before transfer

- Warm two workers, update the source and verify required invalidation/staleness across both.

- Restart one worker or evict its dedicated cache and verify reconstruction without losing identity or queued work.

- Make the shared cache unavailable and verify the agreed failure/fallback behavior rather than silently accepting stale authorization.

[redis.io →](https://redis.io/docs/latest/develop/clients/redis-py/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/deployment/server-workers/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/events/)

Delivery and recovery

### Inspect the source

Inventory API workers, startup resources, database migration runner, durable workers, external scheduler and shared fanout/cache. Worker replication and lifespan resources are not a singleton schedule mechanism.

### During coexistence

Recommendation: keep one schema runner and logical schedule owner while both services operate. Initialize per-process resources deliberately and transfer traffic by a stable domain/user cohort.

### Target design

An explicit FastAPI/Uvicorn process/container deployment, lifespan cleanup, separate durable workers and monitored dependency boundaries. Recommendation: record actual worker count and deployment settings instead of inheriting tutorial values.

### Rollback

Recommendation: preserve the old release and compatible schema, transfer role ownership before restoring traffic, and reconcile work accepted by the new service.

### Benefits and prerequisites

**Recommendation: process/resource ownership makes multi-worker behavior reviewable.**
Requires: Named migration/schedule owners, configured shutdown and tested dependency failure behavior.
Tradeoffs: More workers multiply process-local resources; successful HTTP startup cannot qualify broker, identity or restore behavior.

### Checks before transfer

- Start the intended multi-worker deployment against disposable restored data; exercise authenticated HTTP, one task and cross-worker realtime delivery.

- Terminate a worker during active work, verify shutdown/restart behavior and confirm no extra scheduler or migration runner starts.

[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/advanced/events/)
[fastapi.tiangolo.com →](https://fastapi.tiangolo.com/deployment/server-workers/)
[alembic.sqlalchemy.org →](https://alembic.sqlalchemy.org/en/latest/tutorial.html)
[docs.celeryq.dev →](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html)

[Read the migration workflow →](/rewrite/guide.md)

## Setup

- In a new local source directory: uv init; pin a compatible Python minor; uv add 'fastapi[standard]' sqlalchemy 'psycopg[binary]' alembic pydantic-settings

- uv add --dev ruff mypy pytest httpx

- Create an importable app package with app/main.py exporting app = FastAPI(), request/response models and a health endpoint.

- uv run alembic init migrations; configure environment-based connection URL and target_metadata. Implement per-request/task sessions and domain transaction boundaries.

- uv run alembic revision --autogenerate -m 'initial schema'; manually review, then uv run alembic upgrade head against the development DB.

- Configure the selected identity provider and token verification; implement tenant/object authorization before adding protected endpoints.

- Develop with uv run fastapi dev app/main.py. Package a release with uv sync --locked --no-dev and an explicit production start command; add workers separately when needed.

## Verification

Run these in the configured application; they are instructions, not recorded passes.

```
uv sync --locked
uv run ruff check .
uv run ruff format --check .
uv run mypy app
uv run pytest
uv run alembic check
uv run alembic current
```

## Open questions

- Which identity provider, token validation and tenant authorization model apply?

- Does workload justify async database access, or is synchronous I/O simpler?

- Which host/replica model, upload storage, realtime and worker guarantees apply?

## Sources

- [uv projects](https://docs.astral.sh/uv/guides/projects/)

- [Ruff installation](https://docs.astral.sh/ruff/installation/)

- [mypy getting started](https://mypy.readthedocs.io/en/stable/getting_started.html)

- [ty type checking](https://docs.astral.sh/ty/type-checking/)

- [pytest getting started](https://docs.pytest.org/en/stable/getting-started.html)

- [FastAPI containers](https://fastapi.tiangolo.com/deployment/docker/)

- [SQLAlchemy session basics](https://docs.sqlalchemy.org/en/21/orm/session_basics.html)

- [Alembic autogeneration](https://alembic.sqlalchemy.org/en/latest/autogenerate.html)

- [Pydantic strict mode](https://pydantic.dev/docs/validation/latest/concepts/strict_mode/)

- [FastAPI JWT tutorial](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/)

- [Authlib OAuth web clients](https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html)

- [FastAPI background tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/)

- [Celery tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html)

- [Temporal Python SDK](https://docs.temporal.io/develop/python)

- [uv Docker](https://docs.astral.sh/uv/guides/integration/docker/)

- [FastAPI concurrency](https://fastapi.tiangolo.com/async/)

- [Python logging](https://docs.python.org/3/library/logging.html)

- [Tenacity documentation](https://tenacity.readthedocs.io/en/latest/)

- [FastAPI request files](https://fastapi.tiangolo.com/tutorial/request-files/)

- [FastAPI WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)

- [Boto3 uploads](https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html)

---

Canonical page: https://stack.menu/stacks/python-fastapi/
