We use cookies

We use cookies and similar technologies for analytics and marketing. You can allow these cookies or continue with only essential cookies.

By clicking "Accept", you agree to our use of cookies.
Learn more.

Python SDK

Dependency Injection

🚨

Dependency injection is an experimental feature in Hatchet, and is subject to change.

Hatchet's Python SDK allows you to inject dependencies into your tasks, FastAPI style. These dependencies can be either synchronous or asynchronous functions. They are executed before the task is triggered, and their results are injected into the task as parameters.

This behaves almost identically to FastAPI's dependency injection, and is intended to be used in the same way. Dependencies are useful for sharing logic between tasks that you'd like to avoid repeating, or would like to factor out of the task logic itself (e.g. to make testing easier).

⚠️

Since dependencies are run before tasks are executed, having many dependencies (or any that take a long time to evaluate) can cause tasks to experience significantly delayed start times, as they must wait for all dependencies to finish evaluating.

Usage

To add dependencies to your tasks, import Depends from the hatchet_sdk. Then:

async def async_dep(input: EmptyModel, ctx: Context) -> str:    return ASYNC_DEPENDENCY_VALUEdef sync_dep(input: EmptyModel, ctx: Context) -> str:    return SYNC_DEPENDENCY_VALUE@asynccontextmanagerasync def async_cm_dep(    input: EmptyModel, ctx: Context, async_dep: Annotated[str, Depends(async_dep)]) -> AsyncGenerator[str, None]:    try:        yield ASYNC_CM_DEPENDENCY_VALUE + "_" + async_dep    finally:        pass@contextmanagerdef sync_cm_dep(    input: EmptyModel, ctx: Context, sync_dep: Annotated[str, Depends(sync_dep)]) -> Generator[str, None, None]:    try:        yield SYNC_CM_DEPENDENCY_VALUE + "_" + sync_dep    finally:        pass@contextmanagerdef base_cm_dep(input: EmptyModel, ctx: Context) -> Generator[str, None, None]:    try:        yield CHAINED_CM_VALUE    finally:        passdef chained_dep(    input: EmptyModel, ctx: Context, base_cm: Annotated[str, Depends(base_cm_dep)]) -> str:    return "chained_" + base_cm@asynccontextmanagerasync def base_async_cm_dep(    input: EmptyModel, ctx: Context) -> AsyncGenerator[str, None]:    try:        yield CHAINED_ASYNC_CM_VALUE    finally:        passasync def chained_async_dep(    input: EmptyModel,    ctx: Context,    base_async_cm: Annotated[str, Depends(base_async_cm_dep)],) -> str:    return "chained_" + base_async_cm

In this example, we've declared two dependencies: one synchronous and one asynchronous. You can do anything you like in your dependencies, such as creating database sessions, managing configuration, sharing instances of service-layer logic, and more.

Once you've defined your dependency functions, inject them into your tasks as follows:

@hatchet.task()async def async_task_with_dependencies(    _i: EmptyModel,    ctx: Context,    async_dep: Annotated[str, Depends(async_dep)],    sync_dep: Annotated[str, Depends(sync_dep)],    async_cm_dep: Annotated[str, Depends(async_cm_dep)],    sync_cm_dep: Annotated[str, Depends(sync_cm_dep)],    chained_dep: Annotated[str, Depends(chained_dep)],    chained_async_dep: Annotated[str, Depends(chained_async_dep)],) -> Output:    return Output(        sync_dep=sync_dep,        async_dep=async_dep,        async_cm_dep=async_cm_dep,        sync_cm_dep=sync_cm_dep,        chained_dep=chained_dep,        chained_async_dep=chained_async_dep,    )
⚠️

Important note: Your dependency functions must take two positional arguments: the workflow input and the Context (the same as any other task).

That's it! Now, whenever your task is triggered, its dependencies will be evaluated, and the results will be injected into the task at runtime for you to use as needed.

Last updated on August 11, 2026

On this page