What it is
Koin is a pragmatic dependency injection framework for Kotlin using a DSL, with no code generation, no reflection and no annotation processing.
Declare modules with single, factory and viewModel builders, start Koin at application launch, then inject by type.
Installation
implementation("io.insert-koin:koin-core:4.0.0")Getting started
The smallest useful thing you can do with it, and what each part means.
kotlin
val appModule = module {
single<BookRepository> { SqlBookRepository(get()) } // one instance
single { HttpClient(CIO) }
factory { BookValidator() } // new each time
viewModel { BookListViewModel(get(), get()) }
}
startKoin { modules(appModule) }
// Injection
class BookService : KoinComponent {
private val repo: BookRepository by inject() // lazy
}
// Or by constructor, which is preferable.
class BookService(private val repo: BookRepository)Advanced usage
Where the library earns its place over a simpler alternative.
kotlin
val networkModule = module {
single(named("auth")) { HttpClient { /* with auth */ } }
single(named("public")) { HttpClient() }
scope<UserSession> {
scoped { SessionCache() } // lives as long as the scope
}
}
val client: HttpClient by inject(named("auth"))
// Catch missing bindings in a test rather than at runtime.
class ModuleTest {
@Test
fun `modules resolve`() = checkModules { modules(appModule, networkModule) }
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- NoBeanDefFoundException
- No binding for that type, or a qualifier mismatch. Add it to a module, and add checkModules to catch it earlier next time.
- Koin has not been started
- startKoin was not called, or was called after the first injection. Start it in Application.onCreate or at the top of main.
Best practices
- Always add a checkModules test; it recovers most of what compile-time DI gives you.
- Prefer constructor injection over the KoinComponent by inject() style.
- Use named qualifiers when two bindings share a type.
- Choose Hilt on Android when compile-time safety matters more than build speed.
Background
Why it exists, and what it was reacting to.
Koin trades compile-time verification for simplicity and build speed. Where Dagger and Hilt generate code, Koin resolves at runtime from a declarative module — much faster to build, at the cost of runtime failures for missing bindings.
