Koin - pragmatic dependency injection for Kotlin & Kotlin Multiplatform. Koin DSL or Koin Annotations (JSR-330), compile safe with the Koin Compiler Plugin.
# Koin β Kotlin Dependency Injection Framework
> Pragmatic DI framework for Kotlin and Kotlin Multiplatform. Two styles, one container: Koin DSL or Koin Annotations (JSR-330 compatible). Compile safe in both styles with the Koin Compiler Plugin β no KSP, no kapt, no reflection at its core. Runs on all Kotlin Multiplatform targets.
Concise index: [llms.txt](https://github.com/InsertKoinIO/koin/blob/main/llms.txt). This file is the API cheat sheet.
## Key Facts
- **Version**: Koin 4.2.2, Koin Compiler Plugin 1.2.1, Kotlin 2.3.20 or later
- **Language**: Kotlin (100%)
- **Platforms**: Android, iOS, Desktop, Web (JS/Wasm), Backend (Ktor) via Kotlin Multiplatform
- **License**: Apache 2.0
- **Repository**: https://github.com/InsertKoinIO/koin
- **Website**: https://insert-koin.io
- **Documentation**: https://insert-koin.io/docs/intro/what-is-koin
- **Koin skills (AI agents)**: https://github.com/InsertKoinIO/koin-skills
- **Kotzilla MCP (runtime debugging)**: https://mcp.kotzilla.io/mcp
## IDE Plugin
Official plugin for Android Studio & IntelliJ IDEA β code navigation between definitions and injection points, live safety checks, dependency graph visualization.
**Download:** https://plugins.jetbrains.com/plugin/26131-koin-dependency-injection-official-
## Gradle Dependencies
```kotlin
// BOM (recommended)
plugins {
id("io.insert-koin.compiler.plugin") version "1.2.1" // Koin Compiler Plugin (recommended β compile-time safety)
}
implementation(platform("io.insert-koin:koin-bom:4.2.2")) // BOM resolves every Koin artifact version
implementation("io.insert-koin:koin-core") // Core (all platforms)
implementation("io.insert-koin:koin-annotations") // Annotations style (with the Compiler Plugin)
implementation("io.insert-koin:koin-android") // Android (Context, ViewModel, Scope)
implementation("io.insert-koin:koin-compose") // Compose integration
implementation("io.insert-koin:koin-compose-viewmodel") // Compose ViewModel (koinViewModel)
implementation("io.insert-koin:koin-core-coroutines") // Coroutines (lazy modules)
implementation("io.insert-koin:koin-ktor") // Ktor server
implementation("io.insert-koin:koin-test") // Testing
implementation("io.insert-koin:koin-test-junit5") // JUnit 5 testing
// Never Koin KSP: no com.google.devtools.ksp for Koin, no koin-ksp-compiler, no koin-annotations:2.x pin
```
---
## Starting Koin
### Android
```kotlin
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.androidx.workmanager.koin.workManagerFactory
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@MyApplication)
workManagerFactory() // if using WorkManager
modules(appModule, featureModule)
}
}
}
```
### Annotations (with compile-time graph validation)
```kotlin
import org.koin.core.annotation.KoinApplication
import org.koin.plugin.module.dsl.startKoin // reified startKoin<App> from the Compiler Plugin
@KoinApplication
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin<MyApplication> { // triggers A3 full graph validation
androidLogger()
androidContext(this@MyApplication)
workManagerFactory()
}
}
}
```
### Ktor
```kotlin
import org.koin.ktor.plugin.Koin
fun Application.module() {
install(Koin) {
modules(appModule)
}
}
```
### KMP / Non-Android
```kotlin
import org.koin.core.context.startKoin
startKoin {
modules(commonModule, platformModule)
}
```
---
## Defining Dependencies
### Compiler Plugin DSL (recommended)
Pick one style per project β Koin DSL or Koin Annotations β and don't mix them unless needed (then one style per module).
```kotlin
import org.koin.dsl.module
import org.koin.dsl.bind
import org.koin.plugin.module.dsl.*
val appModule = module {
// Singleton β one instance for app lifetime
single<Database>()
single<UserRepository>()
// Factory β new instance each time
factory<GetUserUseCase>()
// ViewModel β Android ViewModel lifecycle
viewModel<UserViewModel>()
// Worker β WorkManager
worker<SyncWorker>()
// Interface binding
single<UserRepositoryImpl>() bind UserRepository::class
// Multiple bindings
single<MyServiceImpl>() binds arrayOf(ServiceA::class, ServiceB::class)
// Module composition
includes(networkModule, databaseModule)
}
```
### Compiler Plugin DSL with Function Builders (create)
```kotlin
import org.koin.dsl.module
import org.koin.plugin.module.dsl.create
// Builder functions β for wrapping external libraries (Room, Retrofit, etc.)
fun database(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "my-db").build()
fun topicDao(db: AppDatabase): TopicDao = db.topicDao()
fun json(): Json = Json { ignoreUnknownKeys = true }
val databaseModule = module {
single { create(::database) } // parameters auto-resolved from DI
single { create(::topicDao) }
single { create(::json) }
}
```
### Constructor DSL and Classic DSL
Constructor DSL (`singleOf(::T)`) suits projects without the Compiler Plugin. Classic DSL (`single { T(get()) }`) is for custom expressions a constructor or function builder can't express. Both are also checked by the Compiler Plugin when it is applied.
```kotlin
import org.koin.dsl.module
import org.koin.core.module.dsl.*
val appModule = module {
// Constructor DSL β constructor reference
singleOf(::Database)
singleOf(::UserRepository)
factoryOf(::GetUserUseCase)
viewModelOf(::UserViewModel)
// Classic DSL β lambda (manual wiring)
single { Database() }
single { UserRepository(get()) }
factory { GetUserUseCase(get()) }
viewModel { UserViewModel(get()) }
}
```
### Annotations
```kotlin
import org.koin.core.annotation.*
@Singleton
class Database
@Singleton
class UserRepository(private val db: Database)
@Factory
class GetUserUseCase(private val repo: UserRepository)
@KoinViewModel
class UserViewModel(private val useCase: GetUserUseCase) : ViewModel()
// Module with component scan
@Module
@ComponentScan("com.myapp")
class AppModule
// Module with provider functions (for external libraries)
@Module
internal object DatabaseModule {
@Singleton
fun providesDatabase(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "my-db").build()
}
```
### Annotated Top-Level Functions
```kotlin
import org.koin.core.annotation.Singleton
import org.koin.core.annotation.Factory
@Singleton
fun provideDatabase(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "my-db").build()
@Factory
fun provideCache(db: AppDatabase): CacheService = CacheServiceImpl(db)
```
Discovered by `@ComponentScan` like annotated classes.
---
## Injecting Dependencies
### In Android Activity / Fragment
```kotlin
import org.koin.android.ext.android.inject
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel
class MainActivity : ComponentActivity() {
// Lazy injection
private val viewModel: UserViewModel by viewModel()
private val service: MyService by inject()
// Eager injection
val eagerService: MyService = get()
}
```
### In Activity with Scope
```kotlin
import org.koin.android.scope.AndroidScopeComponent
import org.koin.androidx.scope.activityScope
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
class MainActivity : ComponentActivity(), AndroidScopeComponent {
override val scope: Scope by activityScope()
private val viewModel: MainViewModel by viewModel()
private val tracker: ActivityTracker by inject() // scoped to activity lifecycle
}
```
### In Compose
```kotlin
import org.koin.compose.viewmodel.koinViewModel
import org.koin.compose.koinInject
@Composable
fun HomeScreen(viewModel: HomeViewModel = koinViewModel()) {
val analytics: AnalyticsHelper = koinInject()
// ...
}
```
### In Compose with Parameters (Navigation Arguments)
```kotlin
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.parameter.parametersOf
@Composable
fun DetailScreen(
newsId: String,
viewModel: DetailViewModel = koinViewModel(key = newsId) { parametersOf(newsId) }
) {
// Each unique newsId gets its own ViewModel instance
}
```
### In Ktor
```kotlin
import org.koin.ktor.ext.inject
fun Route.userRoutes() {
val service: UserService by inject()
get("/users/{id}") {
val user = service.getUser(call.parameters["id"]!!)
call.respond(user)
}
}
```
### Constructor Injection (Recommended for Business Logic)
```kotlin
// No Koin imports needed β dependencies resolved by the framework
class UserRepository(
private val database: Database,
private val networkClient: NetworkClient
)
class GetUserUseCase(
private val repository: UserRepository
)
```
---
## Qualifiers
### @Named (String Qualifier)
```kotlin
import org.koin.core.annotation.Named
import org.koin.core.qualifier.named
// Definition
@Singleton @Named("local")
class LocalDatabase : Database
@Singleton @Named("remote")
class RemoteDatabase : Database
// Injection
@Singleton
class UserRepository(
@Named("local") private val localDb: Database,
@Named("remote") private val remoteDb: Database
)
// Compiler Plugin DSL β the qualifier stays on the class (@Named above), the definition stays plain
single<LocalDatabase>()
single<RemoteDatabase>()
// Classic DSL only
single<Database>(named("local")) { LocalDatabase() }
```
### Custom @Qualifier (with Parameters)
```kotlin
import org.koin.core.annotation.Qualifier
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class Dispatcher(val type: AppDispatchers)
enum class AppDispatchers { Default, IO }
// Provider
@Singleton @Dispatcher(AppDispatchers.IO)
fun ioDispatcher(): CoroutineDispatcher = Dispatchers.IO
// Consumer
@Singleton
class MyRepository(
@Dispatcher(AppDispatchers.IO) private val dispatcher: CoroutineDispatcher
)
```
---
## Scopes
### DSL Scopes
```kotlin
import org.koin.dsl.module
import org.koin.plugin.module.dsl.scoped
import org.koin.androidx.scope.dsl.activityScope
import org.koin.androidx.scope.dsl.fragmentScope
val appModule = module {
// Activity-scoped
activityScope {
scoped<ActivityTracker>()
}
// Fragment-scoped
fragmentScope {
scoped<FragmentPresenter>()
}
// Custom scope
scope<UserSession> {
scoped<UserRepository>()
scoped<UserPreferences>()
}
}
```
### Annotation Scopes
```kotlin
import org.koin.core.annotation.Scoped
import org.koin.core.annotation.Scope
import org.koin.android.annotation.ActivityScope
import org.koin.android.annotation.FragmentScope
@ActivityScope
class ActivityTracker(val activity: ComponentActivity)
@FragmentScope
class FragmentPresenter(val fragment: Fragment)
@Scope(UserSession::class)
@Scoped
class UserRepository(val db: Database)
```
---
## ViewModel
### With SavedStateHandle
```kotlin
// SavedStateHandle is auto-injected (whitelisted type)
@KoinViewModel
class HomeViewModel(
private val savedStateHandle: SavedStateHandle,
private val repository: UserRepository,
) : ViewModel()
// DSL
viewModel<HomeViewModel>()
```
### With @InjectedParam (Navigation Arguments)
```kotlin
import org.koin.core.annotation.InjectedParam
@KoinViewModel
class DetailViewModel(
private val repository: NewsRepository,
@InjectedParam val newsId: String,
) : ViewModel()
// Compose usage:
koinViewModel(key = newsId) { parametersOf(newsId) }
```
---
## WorkManager
```kotlin
import org.koin.android.annotation.KoinWorker
// Annotations
@KoinWorker
class SyncWorker(
context: Context,
params: WorkerParameters,
private val repository: NewsRepository,
@Dispatcher(AppDispatchers.IO) private val dispatcher: CoroutineDispatcher,
) : CoroutineWorker(context, params)
// DSL
val syncModule = module {
single<WorkManagerSyncManager>() bind SyncManager::class
worker<SyncWorker>()
}
// Bootstrap β add workManagerFactory()
startKoin {
workManagerFactory()
modules(appModule)
}
```
---
## Module Organization
### Annotations β Auto-Discovery
```kotlin
import org.koin.core.annotation.*
// Modules with @Configuration are auto-discovered by startKoin<T>
@Module @ComponentScan("com.myapp.core") @Configuration
class CoreModule
@Module @ComponentScan("com.myapp.feature") @Configuration
class FeatureModule
@Module(includes = [DatabaseModule::class]) @Configuration
class DataModule
// App entry point β assembles all @Configuration modules
@KoinApplication
class MyApplication : Application()
```
### DSL β Explicit Composition
```kotlin
val coreModule = module { single<Database>(); single<NetworkClient>() }
val featureModule = module { includes(coreModule); viewModel<HomeViewModel>() }
val appModule = module {
includes(coreModule, featureModule, syncModule)
}
startKoin { modules(appModule) }
```
### @Configuration Labels (Environment-Specific)
```kotlin
@Module @ComponentScan("com.myapp.core") @Configuration("prod")
class ProdCoreModule
@Module @ComponentScan("com.myapp.core") @Configuration("test")
class TestCoreModule
// Modules with the same label see each other's definitions
```
---
## Dynamic Modules
```kotlin
import org.koin.core.context.loadKoinModules
import org.koin.core.context.unloadKoinModules
// Load at runtime (feature flags, A/B testing)
loadKoinModules(premiumModule)
// Unload when no longer needed
unloadKoinModules(premiumModule)
```
---
## Lazy Modules (Background Loading)
```kotlin
import org.koin.core.context.startKoin
import org.koin.core.lazyModules
startKoin {
modules(criticalModule)
lazyModules(heavyModule, analyticsModule) // loaded in background
}
```
---
## Properties
```kotlin
import org.koin.core.annotation.Property
@Singleton
class ApiClient(
@Property("api_url") val url: String,
@Property("api_key") val key: String
)
// Provide properties
startKoin {
properties(mapOf("api_url" to "https://api.example.com", "api_key" to "secret"))
}
// DSL
single { ApiClient(getProperty("api_url"), getProperty("api_key")) }
```
---
## Optional / Nullable Dependencies
```kotlin
// Nullable param β resolved with getOrNull()
@Singleton
class MyService(
val required: RequiredDep,
val optional: OptionalDep? // null if not in graph
)
// DSL
single<MyService>() // compiler plugin handles getOrNull() automatically
```
---
## Lazy Injection
```kotlin
// Lazy<T> β deferred creation
@Singleton
class MyService(
val heavy: Lazy<HeavyDependency> // created on first access
)
```
---
## List Injection
```kotlin
// List<T> β collects all definitions of type T
@Singleton
class LoggerAggregator(
val loggers: List<LoggerDataSource> // all LoggerDataSource definitions
)
```
---
## Testing
```kotlin
import org.koin.test.KoinTest
import org.koin.test.inject
class MyTest : KoinTest {
private val service: MyService by inject()
@Test
fun testService() {
// service is resolved from Koin
}
}
```
Graph verification is done at compile time by the Koin Compiler Plugin β don't write `checkModules()` / `verify()` tests (on their way to deprecation).
---
## Compile-Time Safety (with Koin Compiler Plugin)
The Koin Compiler Plugin validates your dependency graph at build time:
- **A2 β Per-Module:** validates definitions against visible scope per module
- **A3 β Full Graph:** validates ALL modules at `startKoin<T>()`
- **A4 β Call-Site:** validates every `get<T>()`, `inject<T>()`, `koinViewModel<T>()` call
Works with both DSL and Annotations. Replaces `verify()` / `checkModules()`. If it compiles, it works.
```kotlin
koinCompiler {
compileSafety = true // default
skipDefaultValues = true // default
unsafeDslChecks = true // default
}
```
See https://insert-koin.io/docs/reference/koin-compiler/compile-safety
---
## Architecture
- O(1) resolution via `HashMap.get()` β no reflection, no iteration
- `ConcurrentHashMap` (JVM) / `ConcurrentMutableMap` (Native)
- Fully compatible with R8/ProGuard
- Pure common Kotlin runtime β all KMP targets
## Project Structure
```
koin/projects/
βββ core/ # koin-core (engine), koin-core-viewmodel, koin-core-coroutines, koin-annotations, koin-test*
βββ android/ # koin-android, koin-androidx-workmanager, koin-androidx-startup, koin-dagger-bridgeβ¦
βββ compose/ # koin-compose, koin-compose-viewmodel, koin-compose-navigation3β¦
βββ ktor/ # koin-ktor, koin-logger-slf4j
βββ plugins/ # koin-gradle-plugin
βββ bom/ # koin-bom
```
Building and contributing: https://github.com/InsertKoinIO/koin/blob/main/AGENTS.md
## Related Repositories
- **Compiler Plugin**: https://github.com/InsertKoinIO/koin-compiler-plugin
- **Koin skills (AI agents)**: https://github.com/InsertKoinIO/koin-skills β Claude Code: `/plugin marketplace add InsertKoinIO/koin-skills` then `/plugin install koin@koin-skills`. Other agents (Cursor, Codex, Copilot, Windsurf, Geminiβ¦): `npx skills add InsertKoinIO/koin-skills` (Node.js 22+)
- **Kotzilla MCP**: https://mcp.kotzilla.io/mcp β Koin error diagnosis and runtime debugging (graph behavior, scopes, memory, performance)
- **Playground Apps**: https://github.com/InsertKoinIO/playground-apps
- **Website**: https://insert-koin.io