Skip to content



Lagom is a dependency injection container designed to give you "just enough" help with building your dependencies. The intention is that almost all of your code doesn't know about or rely on lagom. Lagom will only be involved at the top level to pull everything together.


  • Type based auto wiring with zero configuration.
  • Fully based on types. Strong integration with mypy.
  • Minimal changes to existing code.
  • Integration with a few common web frameworks.
  • Support for async python.
  • Thread-safe at runtime

You can see a comparison to other frameworks here


pip install lagom
# or: 
# pipenv install lagom
# poetry add lagom

For the versioning policy and details of what's considered as part of the public interface read here: SemVer in Lagom.


Everything in Lagom is based on types. To create an object you pass the type to the container:

container = Container()
some_thing = container[SomeClass]

Auto-wiring (with zero configuration)

Most of the time Lagom doesn't need to be told how to build your classes. If the __init__ method has type hints then lagom will use these to inject the correct dependencies. The following will work without any special configuration:

class MyDataSource:

class SomeClass:
   #                        👇 type hint is used by lagom
   def __init__(datasource: MyDataSource):

container = Container()
some_thing = container[SomeClass] # An instance of SomeClass will be built with an instance of MyDataSource provided

and later if you extend your class no changes are needed to lagom:

class SomeClass:
   #                                                👇 This is the change.
   def __init__(datasource: MyDataSource, service: SomeFeatureProvider):

# Note the following code is unchanged
container = Container()
some_thing = container[SomeClass] # An instance of SomeClass will be built with an instance of MyDataSource provided

This enables rapid development without worrying too much about configuring lagom. However, long term projects should consider using more explicit configuration

Defining construction

Defining how to build a type when it can't be inferred automatically

If lagom can't infer how to build a type (or you don't want it to), you can instruct the container how to do this.

#                        👇 This lambda gets called each time
container[SomeClass] = lambda: SomeClass("down", "spiral")

if the type needs things from the container the lambda can take a single argument which is the container:

#                            👇 c is the lagom container
container[SomeClass] = lambda c: SomeClass(c[SomeOtherDep], "spinning")

It's important to use the container argument c in the lambda rather than your container instance as lagom builds up layers of containers for caching contexts.

if your construction logic is longer than would fit in a lambda a function can also be bound to the container:

def my_constructor() -> MyComplexDep:
    # Really long
    # stuff goes here
    return MyComplexDep(some_number=5)

Defining a singleton

You may have dependencies that you don't want to be built every time. Any dependency can be configured as a singleton without changing the class at all.

container[SomeClassToLoadOnce] = SomeClassToLoadOnce("up", "left")
alternatively if you want to defer construction until it's needed:

container[SomeClassToLoadOnce] = Singleton(SomeClassToLoadOnce)

Alias a concrete instance to an ABC

If your classes are written to depend on an ABC or an interface but at runtime you want to configure a specific concrete class lagom supports definitions of aliases:

container[SomeAbc] = ConcreteClass

Defining an async loaded type

Lagom fully supports async python. If an async def is used to define a dependency then it will be available as Awaitable[TheDependency]

async def my_constructor() -> MyComplexDep:
    # await some stuff or any other async things
    return MyComplexDep(some_number=5)

my_thing = await container[Awaitable[MyComplexDep]]

Preventing automatic construction

You may have some classes that you never want lagom to construct. For these you can configure an error to be raised on construction:

container[SomeDep] = UnresolvableTypeDefinition("You can't resolve SomeDep because reason")

Connecting lagom

Partially bind a function

In a lot of web frameworks you'll have a function responsible for handling requests. This is a point where lagom can be integrated. A decorator is provided that wraps a function and uses reflection to inject any arguments from the supplied container.

In this example the database will be built automatically by lagom:

def handle_some_request(request, database: DB):
    # Do something in the database with this request

Bind only explicit arguments to the container

The magic_bind_to_container above will try and construct any argument that isn't provided. If you want to be explicit and restrict what lagom injects then an injectable marker is provided. Setting a default value of injectable tells lagom to inject this value if it's not provided by the caller.

from lagom import injectable

def handle_some_request(request: typing.Dict, profile: ProfileLoader = injectable, user_avatar: AvatarLoader = injectable):
    # do something to the game
In this example lagom will only try and inject the profile and user_avatar arguments.

Invocation level caching

If for the life time of a function (maybe a web request) you want a certain class to act as a temporary singleton then lagom has the concept of shared dependencies. When binding a function to a container a list of classes is provided. Each of these classes will only be constructed once per function invocation.

class ProfileLoader:
    def __init__(self, loader: DataLoader):

class AvatarLoader:
    def __init__(self, loader: DataLoader):

@magic_bind_to_container(container, shared=[DataLoader])
def handle_some_request(request: typing.Dict, profile: ProfileLoader, user_avatar: AvatarLoader):
    # do something to the game