Skip to main content
Version: 4.2 - LTS

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.

Good News!

Your annotations stay exactly the same. Only the build configuration and Koin startup code change.

What's Different?​

AspectKSP ProcessingCompiler Plugin
ProcessingKSP (separate step)K2 Compiler (integrated)
Generated filesVisible in build/generated/kspNone - inline transformations
Build speedSlowerFaster
KMP setupPer-platform KSP configurationSingle plugin application
Koin startupmodules(AppModule().module)startKoin<MyApp>()
Future supportDeprecatedActive development

Requirements​

  • Kotlin 2.3.20+ (K2 compiler required)
  • Gradle 8.x+

Migration Steps​

Step 1: Update Kotlin Version​

The Compiler Plugin requires Kotlin 2.3.20+:

// 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 = "1.0.0"

[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" }
note

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 StyleCompiler 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) }
}
note

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​

  1. ./gradlew clean
  2. rm -rf build/generated/ksp
  3. Invalidate IDE caches
  4. Rebuild

Annotations not detected​

Enable logging:

koinCompiler {
userLogs = true
}

Missing dependencies at runtime​

  1. Check @ComponentScan packages
  2. Verify modules in @KoinApplication(modules = [...])
  3. Use @Provided for external dependencies

Migration Checklist​

  • Update Kotlin to 2.3.20+
  • Update Koin to 4.2.0+
  • Remove KSP plugin
  • Remove koin-ksp-compiler dependency
  • Update koin-annotations to main Koin version (io.insert-koin:koin-annotations:$koin_version)
  • Add Koin Compiler Plugin (io.insert-koin.compiler.plugin)
  • Update @KoinViewModel import to org.koin.core.annotation
  • Create @KoinApplication class and replace modules(X().module) with startKoin<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​