Releases: InsertKoinIO/koin-compiler-plugin
1.0.0-RC2
Koin Compiler Plugin 1.0.0-RC2
Stability pass on top of RC1: fixes user-reported crashes on iOS/Native, multi-module dex-merge collisions, and a module load-order behaviour change that makes app-level overrides actually win.
Requires: Kotlin 2.3.x+ (K2) | Koin 4.2.1+
What's New Since 1.0.0-RC1
Cross-module visibility
@Module + @ComponentScanwithout@Configurationnow emits cross-module scan hints — previously scan-covered definitions were invisible to downstreamcompileSafetyunless the module was also@Configuration. See PR #25.@Single(binds = [...])on@Moduleprovider functions preserves binding metadata across module boundaries — consumers can now resolve interfaces bound via provider functions in a dependency JAR. See PR #23 / #22.
Fixes
- Module load order (koin#2402) — auto-discovered
@Configurationmodules now load first and explicit@KoinApplication(modules = [...])load last, so app-level overrides win over dependency defaults under Koin's last-wins semantics. - Duplicate call-site hint classes in multi-module Android builds (#20) — hint filenames are now prefixed with the compilation module identifier; no more
org.koin.plugin.hints.XxxCallsiteKtcollisions at dex merge. - Generic DSL types on iOS/Native (#18) — Kotlin/Native klib signature mangler no longer crashes on generic DSL types (
single<Navigator<Key>>()). Hint emission erases type arguments to match runtime Koin's erasure behaviour. - Arrow
Raise.bind()/ ktorresourceScope { bind() }crash (#17) —collectBindTypenow matches Koin'sbindby FqName, no longer intercepting unrelated librarybindfunctions. single<T> { create(::Impl) }with interface type parameter — the outer<T>is now registered as the provided type (previouslyImpl), sokoin.get<Interface>()compile-safety passes as expected.- Missing DSL-artifact error (RC2.3) —
@KoinViewModel/@KoinWorkerwithout their runtime artifact (koin-core-viewmodel/koin-android-workmanager) now fails the build with a clear message pointing at the missing dependency, instead of silently producing a broken definition. - Unit-returning top-level
@Singletonfunctions (RC2.2) — klib signature-clash fix; two qualified side-effect initializers no longer collide on iOS/JS/Wasm. - Custom qualifier annotations (RC2.1) — plain custom
@Qualifierannotations now produceTypeQualifier, matching runtimenamed<T>()/typeQualifier<T>()semantics.
Documentation
Extended docs on module load order, generic DSL types (with the named<T>() qualifier pattern used by koin-compose-navigation3), and troubleshooting the new missing-artifact compile error.
Behaviour change to note when upgrading
Module load order: if your app declares @KoinApplication(modules = [AppModule::class]) and AppModule defines a binding that is also defined in a @Configuration-discovered dependency module, the app's binding now wins (previously, the dep overrode the app). This is the documented last-wins semantic applied correctly — but if you were relying on the previous behaviour, reorder via an explicit modules = [Dep::class, AppModule::class] list to control load order precisely.
Contributors
Code contributions this release:
- @flaringapp — PR #23: cross-module
@Single(binds=[...])provider functions - @wjz2001 — PR #25: cross-module scan hints without
@Configuration
Ongoing contributors (carried over from RC1):
- Arnaud Giuliani — project lead
- @JellyBrick — caching optimisations (PR #5), Gradle release signing fix
- Kevin Chiu — Gradle plugin package fix
- Youssef Shoaib — runtime annotations provider, build improvements
Issue reporters — the reproductions were excellent, thank you:
- #17 — @gael-ft (Arrow
Raise.bind()crash) - #18 — @alex-z0, @corneloaie (generic iOS crash)
- #20 — @norbertsitko, @tusxxx, @rdietrichberlin (duplicate callsite hints, plus the
setHintPackageworkaround that informed the fix) - #22 — @flaringapp (cross-module
binds) - koin#2402 — @jmartinMone (module load order)
And Francois Dabonot (Kotzilla Slack), whose migration feedback drove the missing-artifact compile error introduced in RC2.3.
1.0.0-RC1
Koin Compiler Plugin 1.0.0-RC1
A native Kotlin Compiler Plugin for Koin dependency injection. Inline compile-time transformations — no generated Kotlin files to manage.
Replaces Koin Annotations (KSP) with a K2 compiler plugin that transforms DSL calls and processes annotations directly in the FIR/IR pipeline. Full Kotlin Multiplatform support.
Requires: Kotlin 2.3.x+ (K2) | Koin 4.2.1+
Features
DSL Transformations
Write idiomatic Koin DSL — the plugin resolves constructors at compile time.
| DSL Call | Description |
|---|---|
single<T>(), factory<T>(), viewModel<T>(), worker<T>(), scoped<T>() |
Definition with automatic constructor resolution |
create(::T) |
Constructor reference in scopes |
startKoin<T>(), koinApplication<T>(), module<T>() |
Application and module loading |
modules(vararg KClass) |
Multi-module loading |
Annotations
Full annotation-driven DI as an alternative (or complement) to DSL.
Definitions — on classes, @Module functions, or top-level functions:
@Singleton, @Factory, @Scoped, @KoinViewModel, @KoinWorker
Modules:
@Module, @ComponentScan, @Configuration (with label-based grouping)
Parameters:
@Named, @Qualifier (string and type), @InjectedParam, @Property, @PropertyValue, @ScopeId, @Provided
Compile-Time Safety
Detect missing or mismatched dependencies at build time — not at runtime.
| Level | Scope |
|---|---|
| A1 | Per-module: local definitions + explicit includes |
| A2 | Configuration group: @Configuration siblings share definitions |
| A3 | Full graph: all modules assembled via startKoin<T>() |
| A4 | Call-site: get<T>(), inject<T>(), koinViewModel<T>() |
| B | DSL modules: single<T>(), factory<T>() in hand-written modules |
| C | Cross-module: definitions from dependency JARs via hint functions |
| D | Properties: @Property/@PropertyValue key matching |
Automatically skipped: nullable params, @InjectedParam, @Provided, @ScopeId, Scope params, default values, List<T>, Android framework types (Context, Application, SavedStateHandle, etc.)
Cross-Module Discovery
Definitions, qualifiers, scopes, and bindings propagate across Gradle modules via lightweight hint functions. No runtime reflection, no classpath scanning.
Kotlin Multiplatform
Full KMP support — JVM, JS, Wasm, Native. Dramatically simplified setup compared to the KSP-based approach (no per-target wiring).
What's New in 1.0.0-RC1
Since 0.6.2:
- Fixed missing binding detection during compile-time safety validation
Since 0.4.x:
@ScopeId— inject dependencies from named or typed scopesScopeparameter injection — pass the Koin scope receiver directly@PropertyValue/@Propertyvalidation with warnings for missing defaults@Providedannotation — mark types as externally available, skip safety validationmodule<T>()andmodules(vararg KClass)DSL interceptionbinds=[]respected to suppress auto-binding (#12)- Actualized IR return types for Wasm/JS targets (#11)
- Performance: cached
referenceFunctions, batched hint file generation
Getting Started
// build.gradle.kts
plugins {
id("io.insert-koin.compiler.plugin") version "1.0.0-RC1"
}
koinCompiler {
compileSafety = true // Compile-time dependency validation (default)
skipDefaultValues = true // Use Kotlin defaults instead of DI resolution (default)
unsafeDslChecks = true // Validate create() lambda safety (default)
userLogs = true // Component detection logs
debugLogs = false // Verbose internal logs
}Migrating from Koin Annotations (KSP)
- Replace
ksp("io.insert-koin:koin-ksp-compiler:...")with the Gradle plugin above - Remove
ksp { }configuration blocks - Delete generated
*Module.ktfiles — the plugin transforms inline - See the full Migration Guide for details
Contributors
- Arnaud Giuliani — project lead
- JellyBrick — caching optimizations (PR #5), Gradle release signing fix
- Kevin Chiu — Gradle plugin package fix
- Youssef Shoaib — runtime annotations provider, build improvements
0.6.2
Koin Compiler Plugin 0.6.2
Compatibility: Kotlin 2.3.20 · Koin 4.2.1-RC1
Bug Fixes
-
Fix #11 — WASM/JS type actualization — Actualize IR return types for generic Koin calls (
Scope.get<T>(),getOrNull<T>(),inject<T>(),getAll<T>(),ParametersHolder.get<T>()). Preventsunbound IrTypeParameterSymbolImplcrashes on WASM/JS/Native targets. (3d9d2d8) -
Fix #12 — Delegation pattern auto-binding — Respect
binds = []to suppress auto-binding. Classes using the delegation pattern (class Decorated(val delegate: MyService) : MyService) with@Singleton(binds = [])no longer cause recursive resolution stack overflows. (78f477c)
Performance
- Cache
referenceFunctions()lookups — Avoid repeated expensive compiler API calls across modules. SameCallableIdqueried N times → 1 real lookup + (N-1) O(1) cache hits. - Cache
@Configurationmodule discovery —discoverConfigurationModulesFromHints()results cached by label set. 10 modules with same labels → 1 discovery instead of 10. - Cache
modulesByFqNamemap — Built once, reused across all module validations. - Batch hint IrFile creation — One
IrFileper module instead of per definition, reducing synthetic file count from O(definitions) to O(modules).
Caching optimizations inspired by @JellyBrick (PR #5) 🙏
Compile Safety
- Phase 3.6 guard — Cross-module call-site hint validation now only runs when a full graph has been assembled (via
@KoinApplication). Prevents false positives in library modules without full graph visibility.
Build
- Gradle signing fix — Only apply signing plugin when
IS_RELEASEis set (PR #4).
0.6.1
Koin Compiler Plugin 0.6.1
Release date: 2026-03-30
New Features
module<T>() and modules(vararg KClass) APIs
Load @Module classes without referencing generated code directly. The compiler plugin intercepts these calls and transforms them at compile time. (#14)
startKoin {
module<NetworkModule>()
modules(DataModule::class, CacheModule::class)
}Requires Koin 4.2.1-beta-1+
@ScopeId Parameter Support
Resolve dependencies from named Koin scopes. Generates getScope("id").get<T>(). Compile safety skips @ScopeId parameters. (#2)
@Factory
class ProfileService(@ScopeId(name = "user_session") val session: UserSession)
// Generates: ProfileService(scope.getScope("user_session").get())@Provided on Parameters
Previously only worked on classes. Now also works on individual constructor parameters to skip compile safety for that specific parameter. (#7)
@Singleton
class MyService(@Provided val ctx: PlatformContext)Scope Parameter Injection
Parameters of type org.koin.core.scope.Scope are automatically injected with the scope receiver. No annotation needed.
@Scoped
class ScopedService(val scope: Scope)
// Generates: ScopedService(scope)@Property/@PropertyValue Validation
Warns at compile time when @Property("key") has no matching @PropertyValue("key") default.
@PropertyValue("api.timeout")
val defaultTimeout = 30
@Factory
class ApiClient(@Property("api.timeout") val timeout: Int) // OK
@Factory
class Other(@Property("missing.key") val value: String) // WARNINGDSL Compile Safety Improvements
- Module reachability validation — Tracks which DSL modules are loaded via
modules()andincludes(). Reports compile errors for definitions in unreachable modules. bind()operator support — Explicitbind(Interface::class)is now tracked for DSL definitions. Auto-binding of supertypes removed for DSL path (matches Koin runtime behavior).create(::function)hints — Provider-only definitions fromcreate(::function)now generate cross-module hints withproviderOnlyflag.- Qualifier propagation in DSL hints —
@Named,@Qualifier, and type qualifiers are now encoded in DSL cross-module hints. - Call-site detection —
by inject()andby viewModel()property delegates in class bodies are now detected for A4 validation.
Bug Fixes
- Fix qualifier propagation in function definition calls
- Fix
@Monitortracing: warn if Kotzilla SDK library is missing - Fix DSL
bind()not being tracked — removingbindnow correctly triggers compile error - Fix
create(::function)not producing cross-module DSL hints - Fix FIR module data null for external library types (e.g., DataStore, CoroutineDispatcher)
- Fix cross-module qualifier encoding with dots in names
Breaking Changes
- DSL auto-binding removed — DSL definitions (
single<T>(),factory<T>()) no longer auto-bind to supertypes. Use explicitbind(Interface::class)to register secondary types. This matches Koin runtime behavior.
Compatibility
| Dependency | Version |
|---|---|
| Koin | 4.2.1-beta-1+ (for module<T>() API), 4.2.0-RC2+ (for other features) |
| Kotlin | 2.3.x+ (K2 compiler required) |
Resolved Issues
0.4.0
Native Kotlin Compiler Plugin for Koin — K2 Required (Kotlin 2.3.x+) | Koin 4.2.0-RC2+
Highlights
Compile-Time Dependency Safety is the headline feature of 0.4.0. The plugin now validates your entire dependency graph at compile time, catching missing bindings before they become runtime crashes.
New Features
Compile-Time Safety Checks (compileSafety = true, on by default)
Multi-layered validation that progressively widens visibility:
- A1 — Per-Module: validates definitions within a single @module plus its explicit includes
- A2 — Configuration Groups: modules sharing a @configuration label are validated together
- A3 — Full Graph (startKoin): validates the complete assembled graph when using @KoinApplication
- A4 — Call-Site Validation: checks get(), inject(), and koinViewModel() call sites against the known graph
- B — DSL Definitions: single(), factory(), etc. participate in the safety graph alongside annotation-based definitions
- C — Cross-Gradle-Module: definitions from dependency JARs are discovered via hint functions
- C2 — Full Hint Metadata: cross-module function hints now carry qualifier, scope, and binding information
Catches missing non-nullable dependencies, unresolved Lazy, qualifier mismatches, and cross-scope errors at compile time. Nullable params, @InjectedParam, @Property, List, and defaulted
parameters are safely skipped.
@provided Annotation
Mark types as externally available at runtime (e.g., platform types not declared as Koin definitions). Safety checks will skip them.
@Provided
class ExternalService // provided by framework at runtime
@Singleton
class MyService(val ext: ExternalService) // no errorAndroid Framework Whitelist
Common Android types are automatically whitelisted — no @provided needed:
Context, Activity, Application, Fragment, SavedStateHandle, WorkerParameters
@monitor Annotation
Function interception for logging and performance monitoring:
@Monitor
class MyService {
fun fetchData(): Data { ... } // calls intercepted with timing/logging
}skipDefaultValues Option (default: true)
Parameters with Kotlin default values are no longer injected from the DI container by default. Annotated and nullable parameters are still resolved normally.
class Service(val a: A, val name: String = "default")
single<Service>()
// Generated: Service(scope.get()) — name uses Kotlin default
Incremental Compilation Support
Dirty marker / IC recompilation detection ensures the plugin cooperates correctly with Kotlin's incremental compilation.
KMP Improvements
- Full hint function generation for JVM, JS, and Wasm targets
- @deprecated(HIDDEN) on generated hints to avoid polluting IDE autocomplete
- Fix for @configuration and @componentscan detection in multi-target builds
- KLIB workaround extended to JS and Wasm targets
Configuration
koinCompiler {
compileSafety = true // Compile-time dependency validation (default: true)
unsafeDslChecks = true // Validate create() is sole lambda instruction (default: true)
skipDefaultValues = true // Skip injection for defaulted params (default: true)
userLogs = true // Component detection logs
debugLogs = true // Verbose internal logs
}Compatibility
- Kotlin: 2.3.x+ (K2 compiler required)
- Koin: 4.2.0-RC2+