Skip to main content

Sub-Dependencies

One of the most powerful features of FastAPI’s dependency injection system is the ability to create sub-dependencies - dependencies that themselves have dependencies. This allows you to build complex, modular systems with clean separation of concerns.

What are Sub-Dependencies?

A sub-dependency is simply a dependency that uses Depends() in its own parameters. FastAPI automatically resolves the entire dependency tree, executing everything in the correct order.
FastAPI builds a complete dependency graph internally using the Dependant model, which tracks all sub-dependencies through its dependencies field (see fastapi/dependencies/models.py:38).

Basic Sub-Dependency Example

Here’s a simple example from the FastAPI source:

How It Works

1

Request arrives

A request comes in to /items/?q=test
2

FastAPI resolves dependencies

FastAPI sees that read_query depends on query_or_cookie_extractor
3

Sub-dependency is resolved first

Before calling query_or_cookie_extractor, FastAPI sees it depends on query_extractor and calls that first
4

Values flow up the chain

The result from query_extractor is passed to query_or_cookie_extractor, and its result is passed to read_query

Multiple Levels of Dependencies

You can nest dependencies as deep as needed:

Dependency Graph

For the above example, FastAPI creates this dependency graph:
Execution order: get_databaseget_sessionget_current_userget_user_permissionsprotected_route

Sub-Dependencies with Multiple Parameters

A dependency can have multiple sub-dependencies:

Dependency Caching

By default, FastAPI caches dependency results within a single request:
The call_count will only increment once per request, even though expensive_operation is used in two different dependencies. This is controlled by the use_cache=True parameter in the Depends class.

Disabling Cache

If you need to disable caching for a specific dependency:

Dependencies with Yield (Context Managers)

Sub-dependencies can use yield to provide cleanup logic. This is especially useful for database sessions:

Execution Flow with Yield

1

Setup phase (before yield)

All dependencies execute their setup code (before yield) in dependency order:
  1. get_db creates database session
  2. get_current_user gets user from database
  3. Path operation executes
2

Cleanup phase (after yield)

After the response is sent, cleanup code (after yield) executes in reverse order:
  1. get_current_user cleanup (if any)
  2. get_db closes database connection

Complex Example: Chained Dependencies

Here’s a real-world example with multiple dependency levels:
This example is directly from the FastAPI source at docs_src/dependencies/tutorial008_py310.py. The cleanup order is:
Always ensure cleanup code in finally blocks doesn’t depend on resources that might already be cleaned up. The reverse execution order helps with this, but be mindful of shared state.

Handling Exceptions in Sub-Dependencies

You can catch exceptions from sub-dependencies:
This pattern (from docs_src/dependencies/tutorial008b_py310.py) allows dependencies to handle exceptions raised during the request processing.

Best Practices

1

Keep dependencies focused

Each dependency should have a single, clear responsibility. This makes them easier to test and reuse.
2

Use meaningful names

Name your dependencies based on what they provide or verify (e.g., get_current_user, verify_permissions).
3

Consider the dependency tree

Think about which dependencies are truly independent and which should be sub-dependencies. This affects caching and execution order.
4

Use yield for resource management

Always use yield with try/finally for dependencies that manage resources like database connections.
5

Be mindful of caching

Remember that dependencies are cached by default. Disable caching with use_cache=False when you need fresh values.

The Dependant Model Structure

Internally, FastAPI tracks sub-dependencies using the Dependant dataclass:
Each Dependant can have its own list of Dependant objects, creating a tree structure that FastAPI traverses to resolve all dependencies.

Next Steps

Now that you understand sub-dependencies, explore:
  • Using dependencies at the path operation decorator level for side effects
  • Setting up global dependencies that apply to your entire application
  • Advanced patterns like dependency override for testing