FastAPI Injectable

FastAPI Injectable

Use FastAPI's Depends() anywhere — in CLI tools, background workers, scheduled jobs, and more.

Stop rewriting your dependency logic. Start reusing it.

PyPI PyPI Downloads Python Version License GitHub Stars

CI Codecov Read the Docs


Installation: pip install fastapi-injectable

Documentation: https://fastapi-injectable.readthedocs.io/en/latest/


Why fastapi-injectable?

If you use FastAPI, you’ve built your app around Depends(). But the moment you need those same dependencies in a CLI command, background worker, Celery task, or scheduled job — you’re stuck. You end up:

  • Duplicating dependency logic outside of routes

  • Introducing a second DI framework alongside FastAPI’s

  • Refactoring hundreds of existing dependency functions

fastapi-injectable fixes this with a single decorator. Your existing Depends() functions just work — everywhere.

Born from a real need: This project solves FastAPI#1105 — a 4+ year old issue requesting Depends() outside routes.

Quick Start

from typing import Annotated

from fastapi import Depends
from fastapi_injectable import injectable

class Database:
    def query(self) -> str:
        return "data"

def get_db() -> Database:
    return Database()

@injectable
def process_data(db: Annotated[Database, Depends(get_db)]) -> str:
    return db.query()

# Use it anywhere!
result = process_data()
print(result) # Output: 'data'

Key Features

Feature

Description

Drop-in decorator

Add @injectable to any function using Depends()

Full async support

Works with sync, async, and mixed dependency chains

Test-friendly

Manual overrides let you swap in mocks instantly

Resource cleanup

Built-in lifecycle management for generator deps

Dependency caching

Optional caching for better performance

App state access

Register your FastAPI app to access app.state in deps

Mypy plugin

Full type-checking support out of the box

Graceful shutdown

Automatic cleanup on program exit via signal handling

Overview

fastapi-injectable is a lightweight package that enables seamless use of FastAPI’s dependency injection system outside of route handlers. It solves a common pain point where developers need to reuse FastAPI dependencies in non-FastAPI contexts like CLI tools, background tasks, or scheduled jobs, allowing you to use FastAPI’s dependency injection system anywhere!

Requirements

  • Python 3.10 or higher (including 3.13t, 3.14t free-threaded builds)

  • FastAPI 0.112.4 or higher

Frequently Asked Questions

Click to expand FAQ

Why would I need this package?

A: If your project heavily relies on FastAPI’s Depends() as the sole DI system and you don’t want to introduce additional DI packages (like Dependency Injector or FastDepends), fastapi-injectable is your friend.

It allows you to reuse your existing FastAPI built-in DI system anywhere, without the need to refactor your entire codebase or maintain multiple DI systems.

Life is short, keep it simple!


Why not directly use other DI packages like Dependency Injector or FastDepends?

A: You absolutely can if your situation allows you to:

  1. Modify large amounts of existing code that uses Depends()

  2. Maintain multiple DI systems in your project

fastapi-injectable focuses solely on extending FastAPI’s built-in Depends() beyond routes. We’re not trying to be another DI system - we’re making the existing one more useful!

For projects with hundreds of dependency functions (especially with nested dependencies), this approach is more intuitive and requires minimal changes to your existing code.

Choose what works best for you!


Can I use it with existing FastAPI dependencies?

A: Absolutely! That’s exactly what this package was built for! fastapi-injectable was created to seamlessly work with FastAPI’s dependency injection system, allowing you to reuse your existing Depends() code anywhere - not just in routes.

Focus on what matters instead of worrying about how to get your existing dependencies outside of FastAPI routes!


Does it work with all FastAPI dependency types?

A: Yes! It supports:

  • Regular dependencies

  • Generator dependencies (with cleanup utility functions)

  • Async dependencies

  • Sync dependencies

  • Nested dependencies (dependencies with sub-dependencies)


What happens to dependency cleanup in long-running processes?

A: You have three options:

  1. Manual cleanup per function: await cleanup_exit_stack_of_func(your_func)

  2. Cleanup everything: await cleanup_all_exit_stacks()

  3. Automatic cleanup on shutdown: setup_graceful_shutdown()


Can I mix sync and async dependencies?

A: Yes! You can freely mix them. For running async code in sync contexts, use the provided run_coroutine_sync() utility.


When should I use async_get_injected_obj() vs get_injected_obj()?

A: Use async_get_injected_obj() when you’re in an async context with a running event loop (like Kafka consumers, async callbacks, or streaming frameworks). Use get_injected_obj() in synchronous code or when no event loop is running.

If you see RuntimeError: This event loop is already running, switch to async_get_injected_obj().

Quick rule of thumb:

  • Already in an async function with a running loop? → Use async_get_injected_obj()

  • In sync code or scripts? → Use get_injected_obj()

See Async Function-based Approach for detailed examples.


Are type hints fully supported for injectable() and get_injected_obj()?

A: Currently, type hint support is available if you are using mypy as your static type checker, you can enable the fastapi-injectable.mypy plugin in your mypy.ini file, or add fastapi_injectable.mypy to your pyproject.toml file, see Type Hinting for more details.


How does caching work?

A: By default, dependencies are cached like in FastAPI routes. You can disable caching with @injectable(use_cache=False) if you need fresh instances.


Is it production-ready?

A: Yes! The package has:

  • 100% test coverage

  • Type checking with mypy

  • Comprehensive error handling

  • Production use cases documented