Back to Koin

Koin for Ktor

docs/reference/koin-ktor/ktor.md

4.2.15.5 KB
Original Source

The koin-ktor module provides dependency injection integration for Ktor applications, working alongside Ktor's built-in DI system.

Why Koin for Ktor?

Ktor 3.4+ includes a built-in DI system. Here's how they compare:

FeatureKtor DIKoin
Basic injectionYesYes
Qualifiers (@Named)YesYes
Property injectionYes (@Property)Yes
Nullable/optional dependenciesYesYes
Scopes (request, custom)NoYes
Module organizationNoYes
Lazy modulesNoYes
Annotation-based componentsNoYes
Compiler plugin verificationNoYes

Ktor DI Limitations

  • No scoping - No request or custom scopes, only singleton-like behavior with cleanup ordering
  • No annotation-based components - No @Singleton, @Factory component scanning like Koin Annotations
  • No compile-time verification - No compiler plugin to verify DI configuration before runtime
  • Limited parameterized types - Cannot resolve parameterized types across type argument subtypes

When to use Koin:

  • Scoped dependencies (request scope, custom scopes)
  • Module-based organization
  • Annotation-based component scanning
  • Compile-time verification with compiler plugin

When Ktor DI is sufficient:

  • Simple applications with few dependencies
  • No scoping requirements
  • Basic qualifier needs

Setup

Add the Koin Ktor dependency:

kotlin
dependencies {
    implementation("io.insert-koin:koin-ktor:$koin_version")
    implementation("io.insert-koin:koin-logger-slf4j:$koin_version") // Optional
}

Declaring Dependencies

Koin supports multiple DSL approaches.

Compiler Plugin DSL

The simplest syntax:

kotlin
val appModule = module {
    single<UserRepositoryImpl>() bind UserRepository::class
    single<UserServiceImpl>() bind UserService::class
}

Annotations

Spring-like with compile-time verification:

kotlin
@Module
@ComponentScan("com.example")
class AppModule

@Singleton
class UserRepositoryImpl : UserRepository

@Singleton
class UserService(private val repository: UserRepository)

Classic DSL

Constructor references:

kotlin
val appModule = module {
    singleOf(::UserRepositoryImpl) bind UserRepository::class
    singleOf(::UserService)
}

Installing the Koin Plugin

Install Koin in your Application module:

kotlin
fun Application.main() {
    install(Koin) {
        slf4jLogger()
        modules(appModule)
    }
}

Complete Configuration

kotlin
fun Application.main() {
    install(Koin) {
        slf4jLogger()
        fileProperties("/application.conf")
        modules(
            networkModule,
            repositoryModule,
            serviceModule
        )
        createEagerInstances()
    }
}

Dependency Injection

Koin provides extension functions for Ktor's core types.

Injection Points

inject() and get() work in:

  • Application
  • Route
  • Routing
  • ApplicationCall (within route handlers)

Application-Level

kotlin
fun Application.main() {
    val helloService by inject<HelloService>()  // Lazy
    val configService = get<ConfigService>()     // Eager

    routing {
        get("/hello") {
            call.respondText(helloService.sayHello())
        }
    }
}

Route-Level

kotlin
fun Route.customerRoutes() {
    val customerService by inject<CustomerService>()

    get("/customers") {
        call.respond(customerService.getAllCustomers())
    }

    get("/customers/{id}") {
        val id = call.parameters["id"]?.toInt()
            ?: return@get call.respond(HttpStatusCode.BadRequest)
        call.respond(customerService.getCustomer(id))
    }
}

Request Handler

kotlin
routing {
    get("/users/{id}") {
        val userService = get<UserService>()
        val userId = call.parameters["id"]!!
        call.respond(userService.getUser(userId))
    }
}

Ktor Events

Monitor Koin lifecycle events:

EventDescription
KoinApplicationStartedKoin container started
KoinApplicationStopPreparingKoin preparing to stop
KoinApplicationStoppedKoin container stopped
kotlin
fun Application.main() {
    install(Koin) {
        slf4jLogger()
        modules(appModule)
    }

    environment.monitor.subscribe(KoinApplicationStarted) {
        log.info("Koin started")
        get<CacheWarmer>().warmUp()
    }

    environment.monitor.subscribe(KoinApplicationStopped) {
        log.info("Koin stopped")
    }
}

Quick Reference

FunctionDescription
install(Koin) { }Install Koin plugin
inject<T>()Lazy injection
get<T>()Eager injection
koinModule { }Declare inline module
koinModules(...)Load existing modules

Documentation

TopicDescription
DI BridgeKoin ↔ Ktor DI integration
Request ScopesRequest-scoped dependencies
TestingTesting Ktor with Koin
Isolated ContextIsolated Koin instances