docs/reference/koin-ktor/ktor.md
The koin-ktor module provides dependency injection integration for Ktor applications, working alongside Ktor's built-in DI system.
Ktor 3.4+ includes a built-in DI system. Here's how they compare:
| Feature | Ktor DI | Koin |
|---|---|---|
| Basic injection | Yes | Yes |
Qualifiers (@Named) | Yes | Yes |
| Property injection | Yes (@Property) | Yes |
| Nullable/optional dependencies | Yes | Yes |
| Scopes (request, custom) | No | Yes |
| Module organization | No | Yes |
| Lazy modules | No | Yes |
| Annotation-based components | No | Yes |
| Compiler plugin verification | No | Yes |
@Singleton, @Factory component scanning like Koin AnnotationsWhen to use Koin:
When Ktor DI is sufficient:
Add the Koin Ktor dependency:
dependencies {
implementation("io.insert-koin:koin-ktor:$koin_version")
implementation("io.insert-koin:koin-logger-slf4j:$koin_version") // Optional
}
Koin supports multiple DSL approaches.
The simplest syntax:
val appModule = module {
single<UserRepositoryImpl>() bind UserRepository::class
single<UserServiceImpl>() bind UserService::class
}
Spring-like with compile-time verification:
@Module
@ComponentScan("com.example")
class AppModule
@Singleton
class UserRepositoryImpl : UserRepository
@Singleton
class UserService(private val repository: UserRepository)
Constructor references:
val appModule = module {
singleOf(::UserRepositoryImpl) bind UserRepository::class
singleOf(::UserService)
}
Install Koin in your Application module:
fun Application.main() {
install(Koin) {
slf4jLogger()
modules(appModule)
}
}
fun Application.main() {
install(Koin) {
slf4jLogger()
fileProperties("/application.conf")
modules(
networkModule,
repositoryModule,
serviceModule
)
createEagerInstances()
}
}
Koin provides extension functions for Ktor's core types.
inject() and get() work in:
ApplicationRouteRoutingApplicationCall (within route handlers)fun Application.main() {
val helloService by inject<HelloService>() // Lazy
val configService = get<ConfigService>() // Eager
routing {
get("/hello") {
call.respondText(helloService.sayHello())
}
}
}
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))
}
}
routing {
get("/users/{id}") {
val userService = get<UserService>()
val userId = call.parameters["id"]!!
call.respond(userService.getUser(userId))
}
}
Monitor Koin lifecycle events:
| Event | Description |
|---|---|
KoinApplicationStarted | Koin container started |
KoinApplicationStopPreparing | Koin preparing to stop |
KoinApplicationStopped | Koin container stopped |
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")
}
}
| Function | Description |
|---|---|
install(Koin) { } | Install Koin plugin |
inject<T>() | Lazy injection |
get<T>() | Eager injection |
koinModule { } | Declare inline module |
koinModules(...) | Load existing modules |
| Topic | Description |
|---|---|
| DI Bridge | Koin ↔ Ktor DI integration |
| Request Scopes | Request-scoped dependencies |
| Testing | Testing Ktor with Koin |
| Isolated Context | Isolated Koin instances |