#1151·uvicorn

support @asynccontextmanager app_factory functions

Author: graingertCreated Aug 13, 2021Updated Oct 27, 2025

Checklist

  • There are no similar issues or pull requests for this yet.
  • I discussed this idea on the community chat and feedback is positive.

Is your feature related to a problem? Please describe.

Currently the lifespan task runs in a sibling task to any request tasks, but a number of use cases require wrapping a context manager around all the request tasks, eg:

Describe the solution you would like.

support app factories like this:

python
@contextlib.asynccontextmanager
async def app_factory() -> AsyncGenerator[App, None]:
    async with anyio.create_task_group() as tg:
        app = FastAPI(__name__)
        app.include_router(items.router)
        yield app

or :

python
var: ContextVar[int] = ContextVar('var', default=42)

@contextlib.asynccontextmanager
async def app_factory():
    token = var.set(999)
    try:
        app = FastAPI(__name__)
        app.include_router(items.router)
        yield app
    finally:
        var.reset(token)

or including the __aenter__/__aexit__ directly on the app instance:

python
class ACMGRFastAPI(FastAPI):
    async def __aenter__(self) -> "ACMGRFastAPI":
        async with AsyncExitStack() as stack:
            self.database = stack.enter_async_context(database())
            self.cache = stack.enter_async_context(cache())
            self.bot = stack.enter_async_context(bot())
            self._stack = stack.pop_all()

        return self

    async def __aexit__(self, *exc_info) -> bool | None:
        return await self._stack.__aexit__(*exc_info)

Describe alternatives you considered

run lifespan as a parent task to all the request tasks

Additional context

see https://gitter.im/encode/community?at=610989bc8fc359158c4f959e

[!IMPORTANT]

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar