Startup DSL

The old startKoin() function has been replaced with a startup DSL. Providing a start function per platform and hiding all options with default parameters was a good quickstart choice, but locked many possibilities of evolution. Now we need to extend and add easily new concepts, and also make definitions loading more efficient.

How do we start Koin in 2.0? Still with the startKoin function, but now you need to declare what you will use:

For Android, don’t forget to declare your AndroidContext with the androidContext function:

Better Performances 🚀

One of the main argument to upgrade to Koin 2.0, is the new engine performances.

Rafa Vázquez has written last year a benchmark project to help measure some performances for DI frameworks. This greatly helped me clearly review the internals. This benchmark runs a project of 400 definitions.

Here is the benchmark for Koin 1.0:

Now with Koin 2.0:

Koin has gained massive performances improvement. You shouldn’t be worried about performances now 😉 In contrary to code generated solution, we need to analyze components at start. But this is very fast to proceed now✨

Definitions & Modules 🛠

The Koin DSL stays the same! It has been simplified by removing features that were not used and implied useless complexity. Then, no more inner modules declaration, weird visibility rules, and the scopes API declaration have been entirely revised.

The main first change that you will notice, is that we don’t use directly strings anymore to name our components. We use qualifiers instead with the named() function. This function can take a string or a type to help qualify a definition or a scope. This gives us a logical name for a component.

// naming with named("mock") instead of "mock"

single<MyRepository>(named(“mock")) { MyMockRepository() }

The additional typing binding DSL operator ( bind ) should be simpler to understand now. Consider that this operator adds a secondary binding type to your definition. To make it clear, let’s see it as an additional “facet” of your definition. The Koin API gets a new bind() function to help you retrieve components declared with this bind operator in your module.

A good example can help to understand:

Loading & unloading modules ♻️

As it’s easy to load modules in Koin (via startKoin or loadKoinModules ), it should be also easy to unload a module. The unloadKoinModules() function helps you drop definitions and instances:

With that, we can handle dynamically Koin modules: load and unload then at will, given the context of your application. Instances drop behind such operation, concern single & scoped definitions.

Some other new incomings in the Koin APIs ✨

Some little stuff that can help you in special cases, required from the community.

You can try to request a component that is not defined, or where instance can’t be resolved:

getOrNull() & injectOrNull()

Other interesting feature, is the ability to add an instance on the fly. Use the declare() function to give an object to Koin. It will declare it as a new Single definition for you:

note: this can be also done for any scope instance.

Koin Isolation ⚙️

The Koin API has been redesigned to allow you create a local instance of Koin. Instead of using the startKoin declaration function which declare your Koin instance into the GlobalContext , use the koinApplication function to declare a local Koin instance.

A local/isolated Koin instance is not registered in the Global Context. In clear, you can’t use directly the standard KoinComponents extensions. You have to specify to use your local instance instead (override the getKoin() function from the KoinComponent interface).

New Scope API ⚠️

A scope is a context with a fixed duration of time, in which an object exists. When the scope ends, any objects bound under that scope cannot be injected again. To better have an image of that, think that a scope is like a box: a space where you put things and throw it when you don’t need it anymore. How do we use the new Scope API?

We now declare & use scopes like that:

In the DSL, a scope define a set of definitions. A scoped definition is a temporary single definition that is inside a scope . To use a scope, we create an instance of a scope . A factory definition is allowed inside a scope, letting it resolve dependencies from the current scope and returning a new instance each time.

The Koin internal design has been completely reviewed around the scope concept: Koin has a main “root” scope and we can have different other scopes around it. Result in the following visibility shadowing rule: Koin will first look at an instance from your scope before looking at a potential definition from the root scope:

Lastly, on any scope instance you can declare a component on the fly:

Load/Unload modules vs Scope API?

With those new features, we have several possibilities to handle components for a limited duration of time. Then use Scope API or not? It depends more on your use case and how you have to manage those instances creation. If you need more fine granularity (time or definitions), the Scope API is more dedicated for that 👍

Stronger Android support ✅

With such a new Scope API, we are able to give you interesting tools for your Android Activities & Fragments. You can easily declare a scope tied to your view, and easily retrieve anything from it with the currentScope property (Koin’s extension for LifecycleOwner components):

The currentScope property is created when you access it and follow the lifecycle of your Android component. It is destroyed when receiving the ON_DESTROY signal.

This Android scope API is present in koin-android-scope and koin-android-viewmodel packages (also for AndroidX).

Lots of fixes have been made for the ViewModel part. The API globally stays the same, but has been simplified:

The name attribute of the definition is used as the ViewModel id

attribute of the definition is used as the ViewModel id Getting a ViewModel instance for a given class can be done directly with getViewModel and by viewModel

and ViewModels can be declared in a scope, to help resolve dependencies from this scope

Working with a ViewModel and a scope is now easier:

Android Experimental Features ✨

The experimental features for Android have been extracted to external packages. You have to setup it with the following packages:

koin-android-ext & koin-androidx-ext

Those experimental features propose a DSL version that doesn’t require you to write your constructor injection function:

It looks nicer but there is no magic. As those experimental APIs rely mainly on reflection to find your constructors, don’t forget to use those pro-guard rules 👉 https://insert-koin.io/docs/2.0/quick-references/experimental-features/#proguard-rule

Helping Java Developers 🚸

The API for Java developers has been simplified (lots more @JvmOverload for the main functions): you don’t need to pass a scope to your API anymore. Just use the KoinJavaComponent as usual:

// lazy inject

Lazy<ComponentA> lazy_a = inject(ComponentA.class); // direct get

ComponentA a = get(ComponentA.class);

You can directly use any scope with a more Java-friendly API:

Scope session = getKoin().createScope("mySession", named("Session_Scope"));



ComponentD d = session.get(ComponentD.class);

Koin as a Ktor feature 👍

For Ktor users, Koin is now delivered as a full Ktor feature:

This way Koin is restarted with all Ktor resources and follow the real lifecycle of the app. The integration is then more standard.