Zero dependencies · typed wiring · no framework lock-in

Small typed dependency injection for Python.

Injex keeps application wiring explicit with normal type hints, scoped lifetimes, test overrides, and graph validation before startup.

Python 3.10–3.13 PEP 561 typed No runtime deps

Background article: Hashnode · DEV

0runtime dependencies
3lifetimes: singleton, transient, scoped
typedconstructor injection from annotations
safegraph validation without object creation

Why it exists

Keep construction at the edge.

Small Python apps often start with direct constructor calls. That is the right default. Injex becomes useful when the same service graph is repeated across API startup, CLI commands, workers, and tests.

Keep one composition root. Keep application code framework-agnostic. Validate the graph before real services are created.

01

Services

Wire repositories, gateways, clients, and use cases once at startup.

02

Workers

Create one scope per job or message while reusing long-lived clients.

03

Tests

Override external dependencies inside one explicit with block.

04

CLIs

Share settings, API clients, and commands without module singletons.

Quick start

Normal Python types. One small container.

Register services at the boundary, validate wiring, then resolve the application service. Constructors stay plain and readable.

from injex import Container

class Repository:
    pass

class Service:
    def __init__(self, repo: Repository):
        self.repo = repo

container = Container()
container.add_singleton(Repository)
container.add_transient(Service)
container.assert_valid()

service = container.resolve(Service)

Positioning

Small by design, useful by contract.

Injex is not a configuration framework. It covers the boring path: typed constructor injection, scoped lifetimes, factories, named registrations, test overrides, and validation without object creation.

Use Injex when

  • one service graph is reused by APIs, CLIs, workers, and tests;
  • test doubles should replace external services explicitly;
  • startup should validate wiring before real objects are built.

Skip it when

  • manual constructor calls are still clear enough;
  • your framework dependency system covers every entrypoint;
  • you need a large provider/configuration DSL.

Documentation

Docs built around decisions, not only API calls.

Python dependency injection

A small Python DI container for explicit service wiring.

Injex is a Python dependency injection container for projects that want typed constructor injection, clean architecture boundaries, startup graph validation, and test overrides without adding a large provider framework.

python dependency injection python di container typed dependency injection clean architecture python