Skip to main content
Dependency Injection (DI) is a design pattern that fundamentally changes how you think about object relationships in your code. Instead of letting an object create its own dependencies internally, you supply them from outside. This single shift makes components loosely coupled, trivially replaceable, and far easier to test. DI is the backbone of modern application architectures, and FastAPI has first-class support for it through its Depends() function — making your API endpoints clean, composable, and side-effect-free.

What is a Dependency?

A dependency is any external object that another object needs to do its job. Common examples:
  • A database connection or session
  • A repository (data access layer)
  • A logger
  • An email service
  • A configuration object
  • An authentication/authorisation service

Without Dependency Injection

When a class creates its own dependencies internally, it becomes tightly coupled to that specific implementation:
Problems with this approach:
  • You cannot test Car without also instantiating Engine.
  • Replacing Engine with a MockEngine or ElectricEngine requires modifying Car’s source code.
  • Behaviour is hidden — the caller cannot control what Car uses internally.

With Dependency Injection

The dependency is supplied from outside — the object receives it rather than creating it:
Now Car only uses the engine — it has no knowledge of how to create one. You can pass any compatible object, including a test double.

Real-World Example: Repository & Service

Without DI — Tightly Coupled

With DI — Loosely Coupled

Later, swapping the data source requires no changes to StudentService:

Benefits of Dependency Injection

Types of Dependency Injection

Constructor Injection (Most Common)

Setter Injection

Method Injection

Constructor injection is strongly preferred because it makes dependencies explicit and ensures the object is always in a valid state from the moment it is created.

FastAPI’s Dependency Injection

FastAPI automates dependency injection for your API routes using the Depends() function:
FastAPI calls get_repository() automatically before executing get_students, and injects the result as the repo parameter.

Chaining Dependencies

You can chain dependencies — services that depend on repositories, for example:
FastAPI resolves the entire dependency graph automatically, creating each dependency in the correct order.
FastAPI also supports generator-based dependencies with yield for resources that need clean-up (like database sessions):
The finally block always runs after the endpoint finishes, guaranteeing the session is closed. This is the context manager pattern applied to dependency injection.