---
title: "Dependency Injection with Kotlin and Koin"
description: "Learn how to implement common dependency injection scenarios with Koin and Kotlin"
authors:
  - name: "Matthew Casperson"
    url: "https://auth0.com/blog/authors/matthew-casperson/"
date: "Sep 21, 2021"
category: "Developers,Tutorial,Kotlin"
tags: ["koin", "kotlin", "Injection"]
url: "https://auth0.com/blog/dependency-injection-with-kotlin-and-koin/"
---

# Dependency Injection with Kotlin and Koin

Inversion of Control (IoC) is a broad term to describe how responsibility for some aspect of a system is lifted out of the custom code written by the end developer and into a framework. [Martin Fowler describes a framework in terms of IoC](https://martinfowler.com/bliki/InversionOfControl.html):

> Inversion of Control is a key part of what makes a framework different from a library. A library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.

A framework embodies some abstract design, with more behavior built-in. In order to use it, you need to insert your behavior into various places in the framework, either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points.

Dependency injection (DI) is one specific example of IoC where classes no longer directly instantiate member properties by creating new objects but instead declare their dependencies and allow an external system, in this case, a dependency injection framework to satisfy those dependencies.

[Koin](https://insert-koin.io/) is a dependency injection framework for Kotlin. It is lightweight, can be used in Android applications, is implemented via a concise DSL, and takes advantage of Kotlin features like delegate properties rather than relying on annotations. 

In this post, we'll look at a simple application taking advantage of Koin to inject dependencies into our custom classes.

## Prerequisites

To build the sample application, you'll need to have JDK 11 or above, which is available from many sources, including [OpenJDK](https://openjdk.java.net/install/), [AdoptOpenJDK](https://adoptopenjdk.net/), [Azul](https://www.azul.com/downloads/), or [Oracle](https://www.oracle.com/au/java/technologies/javase-jdk11-downloads.html).

The code for the sample Koin application can be found [here](https://github.com/mcasperson/KotlinKoinExample).

## The Gradle Project Definition

We start with the Gradle build file, which includes dependencies for Kotlin and Koin, and makes use of the [shadow plugin](https://github.com/johnrengelman/shadow) to create self-contained uberjars:

```groovy
buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
    }
}

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.5.21"
}

apply plugin: 'kotlin'
apply plugin: 'com.github.johnrengelman.shadow'

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.21"
    implementation "io.insert-koin:koin-core:3.1.2"
}
```

To build the uberjar, run this command from Bash or PowerShell:

```bash
./gradlew shadowJar
```

## Registering Singletons

The first demonstration of Koin will register a class as a singleton, ensuring each time we request a new instance of the class, we are returned a single, shared object. Here is the code from the file `single.kt`:

```kotlin
// src/main/kotlin/com/matthewcasperson/single.kt

package com.matthewcasperson

import org.koin.core.context.GlobalContext.startKoin
import org.koin.dsl.module

class SingleInstance {
    companion object {
        var count: Int = 0
    }

    init {
        ++count
    }

    fun hello() = "I am instance number $count"
}

fun main() {
    val singleModule = module {
        single { SingleInstance() }
    }

    var app = startKoin {
        modules(singleModule)
    }

    println(app.koin.get<SingleInstance>().hello())
    println(app.koin.get<SingleInstance>().hello())
    println(app.koin.get<SingleInstance>().hello())
}
```

This class is run with the command:

```bash
java -cp ./build/libs/KotlinKoinExample-all.jar com.matthewcasperson.SingleKt
```

We start by defining a typical class, but with a companion object containing a variable called `count`. The `count` variable is incremented by 1 each time we create a new `SingleInstance` object, which we will use to track how many new `SingleInstance` objects have been created:

```kotlin
class SingleInstance {
    companion object {
        var count: Int = 0
    }

    init {
        ++count
    }

    fun hello() = "I am instance number $count"
}
```

Inside the `main` function we create a [Koin module](https://insert-koin.io/docs/reference/koin-core/modules/). Modules are used to group related Koin definitions, and here we use the `single` definition to instruct Koin to create a single instance of the supplied object:

```kotlin
fun main() {
    val singleModule = module {
        single { SingleInstance() }
    }
```

Next we call the `startKoin` function, which is part of the `GlobalContext` object. `GlobalContext` is a singleton (defined as an [object declaration](https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview)), and is typically used as the default context for applications. Here we register our module into the global context:

```kotlin
    var app = startKoin {
        modules(singleModule)
    }
```

We're now able to request instances of any of our registered objects with `app.koin.get`. To demonstrate that our `single` definitions are working as expected, we get an instance of the `SingleInstance` class three times and print the message containing the instance count to the console: 

```kotlin
    println(app.koin.get<SingleInstance>().hello())
    println(app.koin.get<SingleInstance>().hello())
    println(app.koin.get<SingleInstance>().hello())
}
```

The output shows we have been given the same `SingleInstance` object each time:

```bash
I am instance number 1
I am instance number 1
I am instance number 1
```

## Registering a Factory

There are times when you want a new instance each time you request a dependency from Koin. To support this, Koin has a `factory` definition. This is demonstrated in the file `factory.kt`:

```kotlin
// src/main/kotlin/com/matthewcasperson/factory.kt

package com.matthewcasperson

import org.koin.core.context.GlobalContext.startKoin
import org.koin.dsl.module

class FactoryInstance {
    companion object {
        var count: Int = 0
    }

    init {
        ++count
    }

    fun hello() = "I am instance number $count"
}

fun main() {
    val factoryModule = module {
        factory { FactoryInstance() }
    }

    var app = startKoin {
        modules(factoryModule)
    }

    println(app.koin.get<FactoryInstance>().hello())
    println(app.koin.get<FactoryInstance>().hello())
    println(app.koin.get<FactoryInstance>().hello())
}
```

This class is run with the command:

```bash
java -cp ./build/libs/KotlinKoinExample-all.jar com.matthewcasperson.FactoryKt
```

This code is almost a line for line copy of the previous example, with some different class and variable names. The most significant difference is how the module is built, where we use the `factory` definition:

```kotlin
    val factoryModule = module {
        factory { FactoryInstance() }
    }
```

Whereas the `single` definition registered a singleton dependency, the `factory` definition calls the supplied lambda every time a dependency is requested.

This is reflected in the console output, which shows that we have indeed constructed three instances, one for each call to `app.koin.get`:

```bash
I am instance number 1
I am instance number 2
I am instance number 3
```

## Registering Interfaces

The previous two examples registered concrete classes with Koin, but good object-oriented practice is to work with interfaces rather than classes. The example below from the file `interfaces.kt` shows how to register a class via its base interface with Koin:

```kotlin
// src/main/kotlin/com/matthewcasperson/interfaces.kt

package com.matthewcasperson

import org.koin.core.context.GlobalContext.startKoin
import org.koin.dsl.module

interface HelloService {
    fun hello(): String
}

class HelloServiceImpl : HelloService {
    override fun hello() = "Hello!"
}

fun main() {
    val helloService = module {
        single { HelloServiceImpl() as HelloService }
    }

    var app = startKoin {
        modules(helloService)
    }

    println(app.koin.get<HelloService>().hello())
}
```

This class is run with the command:

```bash
java -cp ./build/libs/KotlinKoinExample-all.jar com.matthewcasperson.InterfacesKt
```

We start with a basic interface:

```kotlin
interface HelloService {
    fun hello(): String
}
```

We then implement the interface in a class:

```kotlin
class HelloServiceImpl : HelloService {
    override fun hello() = "Hello!"
}
```

To make the class available to Koin via its interface, we cast the new object back to the interface with the `as` operator while building the module:

```kotlin
    val helloService = module {
        single { HelloServiceImpl() as HelloService }
    }
```

We then retrieve a dependency from its interface:

```kotlin
    println(app.koin.get<HelloService>().hello())
```

## Resolving Nested Dependencies

All the previous examples have resolved objects with no additional dependencies. A more typical scenario is where Koin is used to resolve classes that themselves have additional dependencies. This is demonstrated in the file called `nested.kt`:

```kotlin
// src/main/kotlin/com/matthewcasperson/nested.kt

package com.matthewcasperson

import org.koin.core.context.GlobalContext.startKoin
import org.koin.dsl.module

data class HelloMessageData(val message : String = "Hello from wrapped class!")

interface HelloServiceWrapper {
    fun hello(): String
}

class HelloServiceWrapperImpl(private val helloMessageData:HelloMessageData) : HelloServiceWrapper {
    override fun hello() = helloMessageData.message
}

fun main() {
    val helloService = module {
        single { HelloMessageData() }
        single { HelloServiceWrapperImpl(get()) as HelloServiceWrapper }
    }

    var app = startKoin {
        modules(helloService)
    }

    println(app.koin.get<HelloServiceWrapper>().hello())
}
```

This class is run with the command:

```bash
java -cp ./build/libs/KotlinKoinExample-all.jar com.matthewcasperson.NestedKt
```

We start with a data class defining a string property:

```kotlin
data class HelloMessageData(val message : String = "Hello from wrapped class!")
```

As with the previous example, we define an interface and then implement the interface with a class. This time, however, the class has a constructor that takes an instance of `HelloMessageData`:

```kotlin
interface HelloServiceWrapper {
    fun hello(): String
}

class HelloServiceWrapperImpl(private val helloMessageData:HelloMessageData) : HelloServiceWrapper {
    override fun hello() = helloMessageData.message
}
```

When defining the module, we register an instance of the `HelloMessageData` class, and then resolve that class in the `HelloServiceWrapperImpl` constructor with a call to `get`, which will return the appropriate dependency for us. Note the order is not important here, and `HelloServiceWrapperImpl` could have been defined in the module first:

```kotlin
    val helloService = module {
        single { HelloMessageData() }
        single { HelloServiceWrapperImpl(get()) as HelloServiceWrapper }
    }
```

## Creating a KoinComponent

We noted earlier that Koin creates a default global context that our dependencies are registered with. Koin uses this global context, in conjunction with Kotlin [delegated properties](https://kotlinlang.org/docs/delegated-properties.html), through the `KoinComponent` interface to allow classes to resolve their own dependencies without an explicit reference to the `KoinApplication` returned by `startKoin`. An example of this is shown in the file `koinComponent.kt`:

```kotlin
// src/main/kotlin/com/matthewcasperson/koinComponent.kt

package com.matthewcasperson

import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.context.GlobalContext.startKoin
import org.koin.dsl.module

data class GoodbyeMessageData(val message : String = "Goodbye!")

interface GoodbyeService {
    fun goodbye(): String
}

class GoodbyeServiceImpl(private val goodbyeMessageData: GoodbyeMessageData) : GoodbyeService {
    override fun goodbye() = "GoodbyeServiceImpl says: ${goodbyeMessageData.message}"
}

class GoodbyeApplication : KoinComponent {
    val goodbyeService by inject<GoodbyeService>()
    fun sayGoodbye() = println(goodbyeService.goodbye())
}

fun main() {
    val goodbyeModule = module {
        single { GoodbyeMessageData() }
        single { GoodbyeServiceImpl(get()) as GoodbyeService }
    }

    startKoin {
        modules(goodbyeModule)
    }

    GoodbyeApplication().sayGoodbye()
}
```

This class is run with the command:

```bash
java -cp ./build/libs/KotlinKoinExample-all.jar com.matthewcasperson.KoinComponentKt
```

This example draws from the features demonstrated in previous sections to define a class called `GoodbyeServiceImpl`, with a nested dependency on the data class called `GoodbyeMessageData`, and which implements an interface called `GoodbyeService`:

```kotlin
data class GoodbyeMessageData(val message : String = "Goodbye!")

interface GoodbyeService {
    fun goodbye(): String
}

class GoodbyeServiceImpl(private val goodbyeMessageData: GoodbyeMessageData) : GoodbyeService {
    override fun goodbye() = "GoodbyeServiceImpl says: ${goodbyeMessageData.message}"
}
```

We then define a class called `GoodbyeApplication` implementing the `KoinComponent` interface. This class has a delegate property called `goodbyService` initialized by the `inject` function made available through the `KoinComponent` interface:

```kotlin
class GoodbyeApplication : KoinComponent {
    val goodbyeService by inject<GoodbyeService>()
    fun sayGoodbye() = println(goodbyeService.goodbye())
}
```

The module is defined in much the same way as it has been in previous examples. Note however that the `GoodbyeApplication` class is not defined in the module:

```kotlin
    val goodbyeModule = module {
        single { GoodbyeMessageData() }
        single { GoodbyeServiceImpl(get()) as GoodbyeService }
    }
```

In this example, we don't assign the result of the `startKoin` function to any variable; registering the module with the global context is enough here:

```kotlin
    startKoin {
        modules(goodbyeModule)
    }
```

We then create a new instance of the `GoodbyeApplication` class and call its `sayGoodbye` function. By implementing the `KoinComponent` interface, the `GoodbyeApplication` class can resolve its own dependencies from the global context and will resolve its `GoodbyeService` dependency in order to print a message to the console:

```kotlin
    GoodbyeApplication().sayGoodbye()
```

The `KoinComponent` interface is convenient, but be aware that it means your classes are now dependant on the Koin framework. Constructor-based injection is recommended when you wish to share code without any explicit dependency on Koin. 

## Conclusion

Koin is a lightweight dependency injection framework with a concise DSL taking advantage of Kotlin's modern syntax and features. In this post, we looked at how Koin creates singletons and factories, registers dependencies against their interfaces, and allows classes to resolve their own dependencies with delegated properties.