A practical dependency-injection structure for FastAPI that controls lifetimes and configuration while keeping application and domain code framework-independent.

Production principle

Use Depends at the HTTP composition boundary, then pass ordinary Python objects into framework-independent use cases.

Degraded
class OrderService:
    def create(self, data: dict):
        settings = get_settings()
        db = next(get_db())
        carrier = Depends(get_carrier)
        ...
Repaired
def get_order_service(
    uow: UnitOfWork = Depends(get_uow),
    carrier: Carrier = Depends(get_carrier),
) -> OrderService:
    return OrderService(uow=uow, carrier=carrier)

@router.post("/orders")
def create(command: CreateOrder, service: OrderService = Depends(get_order_service)):
    return service.create(command)
01

Keep Depends at the edge

Depends is interpreted by FastAPI while resolving a request. Using it inside ordinary classes does not inject anything and makes those classes dependent on a lifecycle they cannot control.

Provider functions belong near the API adapter. They translate request scope into ordinary constructor arguments: a unit of work, authenticated actor, clock or external gateway. The application service itself remains normal Python and can be instantiated directly in tests and workers.

02

Define lifetime deliberately

Database sessions are usually request-scoped; configuration and connection pools are commonly application-scoped; mutable use-case state should rarely be shared. Mixing these lifetimes creates leaked sessions, stale state and unsafe concurrent access.

Use yield-based dependencies for resources whose cleanup must run after the request. Do not hide commit inside cleanup: a response should not be produced before the application knows whether its transaction succeeded.

03

Override providers, not behaviour

FastAPI dependency overrides are useful for API integration tests, but most business tests should construct the service with fakes directly. This keeps failures focused and reduces framework setup.

The production gate should show that providers use validated configuration, resource cleanup executes on errors and the same application service can run from HTTP, a worker or a command without importing FastAPI.

Review checklist

Evidence to take into review

  • Depends appears only in FastAPI adapters and provider functions.
  • Object lifetime is documented for sessions, clients and services.
  • Cleanup runs for both successful and failed requests.
  • Business tests instantiate services without the framework.
  • Transactions complete before a successful response is returned.
Continue the inspection

Explore all engineering notes.

Use PRODUCTION-7 to connect this concern with the other dimensions of a trustworthy backend.

View all articles Get the checklist