Skip to main content
Version: 4.2

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+ (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" }
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