Migrating Koin Annotations: KSP to Compiler Plugin
This guide helps you migrate your Koin Annotations project from KSP-based processing to the new Koin Compiler Plugin.
Your annotations stay exactly the same. Only the build configuration and Koin startup code change.
What's Different?
| Aspect | KSP Processing | Compiler Plugin |
|---|---|---|
| Processing | KSP (separate step) | K2 Compiler (integrated) |
| Generated files | Visible in build/generated/ksp | None - inline transformations |
| Build speed | Slower | Faster |
| KMP setup | Per-platform KSP configuration | Single plugin application |
| Koin startup | modules(AppModule().module) | startKoin<MyApp>() |
| Future support | Deprecated | Active development |
Requirements
- Kotlin 2.3+ (K2 compiler required)
- Gradle 8.x+
Migration Steps
Step 1: Update Kotlin Version
The Compiler Plugin requires Kotlin 2.3+:
// build.gradle.kts
plugins {
kotlin("jvm") version "2.3.20" // 2.3.20 minimum
}
Step 2: Update Version Catalog
Before (KSP):
[versions]
koin = "4.0.0"
koin-ksp = "2.0.0" # Separate versioning for KSP annotations
ksp = "2.0.0-1.0.22"
[libraries]
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin-ksp" }
koin-ksp-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-ksp" }
[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
After (Compiler Plugin):
[versions]
koin = "4.2.0"
koin-plugin = "0.4.1"
[libraries]
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" }
[plugins]
koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" }
koin-annotations is now part of the main Koin project and uses the same version as koin-core.
Step 3: Update Build Configuration
Before (KSP):
// build.gradle.kts
plugins {
alias(libs.plugins.ksp)
}
dependencies {
implementation(libs.koin.core)
implementation(libs.koin.annotations) // KSP version (separate versioning)
ksp(libs.koin.ksp.compiler)
}
ksp {
arg("KOIN_CONFIG_CHECK", "true")
}
After (Compiler Plugin):
// build.gradle.kts
plugins {
alias(libs.plugins.koin.compiler)
}
dependencies {
implementation(libs.koin.core)
implementation(libs.koin.annotations) // Same version as koin-core
}
// Optional configuration
koinCompiler {
userLogs = true // Log component detection
}
Step 4: Update Koin Startup
This is the main code change. The KSP approach uses generated .module extensions, while the Compiler Plugin uses @KoinApplication with typed APIs.
Before (KSP):
import org.koin.ksp.generated.* // Generated extensions
@Module
@ComponentScan("com.myapp")
class AppModule
fun main() {
startKoin {
modules(AppModule().module) // Generated .module extension
}
}
After (Compiler Plugin):
// No generated imports needed
@Module
@ComponentScan("com.myapp")
class AppModule
@KoinApplication(modules = [AppModule::class])
class MyApp
fun main() {
startKoin<MyApp>() // Typed API
}
Android Example
Before (KSP):
import org.koin.ksp.generated.*
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApplication)
modules(AppModule().module)
}
}
}
After (Compiler Plugin):
@KoinApplication(modules = [AppModule::class])
class MyApp
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin<MyApp> {
androidContext(this@MyApplication)
}
}
}
Step 5: Clean Up
Remove KSP-generated files and rebuild:
rm -rf build/generated/ksp
./gradlew clean build
Annotations Stay the Same
All your annotated classes remain unchanged:
// No changes needed!
@Singleton
class UserRepository(private val database: Database)
@Factory
class GetUserUseCase(private val repository: UserRepository)
@KoinViewModel
class UserViewModel(private val useCase: GetUserUseCase) : ViewModel()
@Module
@ComponentScan("com.myapp")
class AppModule
All annotations work identically. See Annotations Reference for the complete list.
Import Change: @KoinViewModel
The @KoinViewModel annotation package has changed:
// Before (KSP)
import org.koin.android.annotation.KoinViewModel
// After (Compiler Plugin)
import org.koin.core.annotation.KoinViewModel
Top-Level Function Definitions (New)
The Compiler Plugin supports annotations on top-level functions, discovered by @ComponentScan:
@Singleton
fun provideDatabase(): DatabaseService = PostgresDatabase()
@Factory
fun provideCache(db: DatabaseService): CacheService = RedisCache(db)
@Module
@ComponentScan("com.myapp")
class AppModule
Function return type determines the binding type. Function parameters are injected as dependencies.
DSL Syntax Changes
If you use Koin DSL modules alongside annotations, the Compiler Plugin introduces a cleaner syntax:
| KSP / Classic Style | Compiler Plugin Style |
|---|---|
singleOf(::MyService) | single<MyService>() |
factoryOf(::MyRepo) | factory<MyRepo>() |
viewModelOf(::MyVM) | viewModel<MyVM>() |
scopedOf(::MyScoped) | scoped<MyScoped>() |
workerOf(::MyWorker) | worker<MyWorker>() |
single { fn(get()) } | single { create(::fn) } |
// Before
val myModule = module {
singleOf(::MyService)
factoryOf(::MyRepository)
viewModelOf(::MyViewModel)
}
// After
import org.koin.plugin.module.dsl.*
val myModule = module {
single<MyService>()
factory<MyRepository>()
viewModel<MyViewModel>()
}
// Function builders — for external libraries (Room, Retrofit, etc.)
fun createDatabase(context: Context): AppDatabase =
Room.databaseBuilder(context, AppDatabase::class.java, "db").build()
val dbModule = module {
single { create(::createDatabase) }
}
The Compiler Plugin DSL is in package org.koin.plugin.module.dsl. Classic DSL remains in org.koin.dsl.
Cross-Module Discovery
Use @Configuration for automatic module discovery across Gradle modules:
// In feature module
@Module
@ComponentScan
@Configuration
class FeatureModule
// In app module - FeatureModule is auto-discovered
@KoinApplication
object MyApp
startKoin<MyApp>() // FeatureModule automatically included
KMP Migration
The Compiler Plugin greatly simplifies KMP setup.
Before (KSP) - Per-platform configuration:
// shared/build.gradle.kts
plugins {
kotlin("multiplatform")
id("com.google.devtools.ksp")
}
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.insert-koin:koin-core:$koin_version")
implementation("io.insert-koin:koin-annotations:$koin_ksp_version") // Separate version
}
}
}
dependencies {
// KSP compiler required for each platform
add("kspAndroid", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
add("kspIosX64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
add("kspIosArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
add("kspIosSimulatorArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
}
After (Compiler Plugin) - Single plugin:
// shared/build.gradle.kts
plugins {
kotlin("multiplatform")
alias(libs.plugins.koin.compiler)
}
kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.koin.core)
implementation(libs.koin.annotations)
}
}
}
Typed Startup APIs
The Compiler Plugin provides typed APIs: startKoin<T>(), koinApplication<T>(), koinConfiguration<T>().
See Starting with Annotations for details.
Configuration Labels (New)
The Compiler Plugin adds configuration labels for conditional module loading.
See Modules - Configuration for details.
Compiler Plugin Options
See Compiler Plugin Options for all configuration options.
Troubleshooting
Build fails after removing KSP
./gradlew cleanrm -rf build/generated/ksp- Invalidate IDE caches
- Rebuild
Annotations not detected
Enable logging:
koinCompiler {
userLogs = true
}
Missing dependencies at runtime
- Check
@ComponentScanpackages - Verify modules in
@KoinApplication(modules = [...]) - Use
@Providedfor external dependencies
Migration Checklist
- Update Kotlin to 2.3.20+
- Update Koin to 4.2.0+
- Remove KSP plugin
- Remove
koin-ksp-compilerdependency - Update
koin-annotationsto main Koin version (io.insert-koin:koin-annotations:$koin_version) - Add Koin Compiler Plugin (
io.insert-koin.compiler.plugin) - Update
@KoinViewModelimport toorg.koin.core.annotation - Create
@KoinApplicationclass and replacemodules(X().module)withstartKoin<MyApp>() - Update DSL imports to
org.koin.plugin.module.dsl.*if using DSL modules - Update DSL syntax:
singleOf(::X)→single<X>() - Remove
import org.koin.ksp.generated.* - Clean and rebuild (
rm -rf build/generated/ksp && ./gradlew clean build)
See Also
- Compiler Plugin Setup - Complete setup guide
- Annotations Reference - All annotations
- KSP Setup (Deprecated) - Legacy reference