Koin Compiler Plugin - Roadmap
July 29, 2026 · View on GitHub
Project status, completed work, and future plans.
Completed
- Implement reified type parameter syntax
single<T>(),factory<T>(), etc. - Implement
Scope.create(::T)constructor reference syntax - Implement
worker<T>()DSL for Android WorkManager - Make
plugin-supporta full KMP library (all Koin targets, requires Koin 4.2.0-beta3+) - Create stub classes for ViewModel and ListenableWorker (avoid runtime dependencies)
- Gradle plugin auto-injects
koin-annotationsdependency (needs KMP support) - Move samples to separate folder for independent Kotlin version
- Add Kotlin 2.2.x workarounds (stdlib for JS/WASM, disable metadata compilation)
- Deprecate
org.koin.android.annotation.KoinViewModel - Implement
@Configurationcross-module discovery via hint functions - Fix KMP multi-phase FIR compilation (unique synthetic file names per class)
- Fix expect/actual class handling (skip expect classes in FIR)
- Fix K/Native synthetic file generation (skip on Native targets)
- Fix cross-source-set module resolution (fallback via context.referenceFunctions)
- Fix object module support (use irGetObject instead of constructor)
- Add configurable logging (userLogs for component detection, debugLogs for internal processing)
- Implement
koinConfiguration<T>()DSL transformation - Implement
KoinApplication.withConfiguration<T>()extension transformation - Implement
@PropertyValueannotation for property defaults - Support definition annotations on top-level functions (discovered by
@ComponentScan)
Phase 1: Packaging & Publishing ✅
Prepared for public release on Maven Central.
1.1 Build Configuration
- Review and finalize artifact coordinates
- Ensure proper module structure for publishing
- Add LICENSE file (Apache 2.0)
- Add README.md with usage instructions
1.2 Maven Central Publishing
- Configure
maven-publishplugin for all modules - Set up GPG signing for artifacts
- Configure Sonatype OSSRH credentials
- Add POM metadata (description, license, developers, SCM URLs)
- Publish artifacts:
compiler-plugin,gradle-plugin- Note:
plugin-supportis included in Koin (koin-annotations), not published separately
- Note:
1.3 Gradle Plugin Portal
- Register plugin ID on Gradle Plugin Portal
- Configure
java-gradle-pluginpublishing - Test plugin resolution via
plugins { id("io.insert-koin.compiler.plugin") }
1.4 CI/CD & Release Process
- Set up GitHub Actions for CI (build, test)
- Automated release workflow (tag -> publish)
- Version management strategy (semver)
1.5 Multi-Kotlin Version Strategy
- Deferred: Will follow latest Kotlin versions and adapt as needed
- No complex versioning scheme required for now
Phase 2: Compile-Time Safety & Monitoring (Current)
Advanced features for production reliability.
2.1 @PropertyValue Default Values ✅
Support default values for property injection:
-
@PropertyValue("key")annotation on constant - Generate
getProperty("key", defaultValue)calls
@PropertyValue("api.timeout")
val DEFAULT_TIMEOUT = 30000
@Factory
class ApiClient(@Property("api.timeout") val timeout: Int)
// Generates: factory { ApiClient(getProperty("api.timeout", DEFAULT_TIMEOUT)) }
2.2 Skip Default Values ✅
Skip DI injection for parameters with Kotlin default values:
-
skipDefaultValuesoption inkoinCompiler { }DSL (default:true) - Non-nullable parameters with defaults use Kotlin default value
- Nullable parameters still use
getOrNull()regardless - Annotated parameters (
@Named,@Qualifier, etc.) always injected - User log traces when parameters are skipped
class Service(val a: A, val name: String = "default")
single<Service>()
// With skipDefaultValues=true: Service(scope.get()) -- name uses default
// With skipDefaultValues=false: Service(scope.get(), scope.get())
2.3 Compile-Time Dependency Validation ✅
Detect missing dependencies at compile time instead of runtime crashes.
-
Per-module validation (A1): local definitions + explicit includesRemoved in 1.1.0 — a module validated in isolation cannot know how it's wired into a larger app; superseded by A3 as the sole verifier (seedocs/COMPILE_TIME_SAFETY.md,docs/COMPILE_SAFETY_A3_PLAN.md) - Validate non-nullable parameters have definitions
- Validate
Lazy<T>inner type is provided - Validate
@Named/@Qualifierqualifiers match (with hints for mismatches) - Validate scoped dependencies are in correct scope
- Skip safe parameters: nullable,
@InjectedParam,@Property,List<T>, defaults - Clear error messages with module/parameter context
-
Configuration group validation (A2):Removed in 1.1.0 along with A1 —@Configurationsibling modules share definitions@Configurationis now purely a module-discovery signal for A3 - startKoin full-graph validation (A3): validates all modules assembled by
startKoin<T>()— the sole compile-safety verifier as of 1.1.0 - Cross-Gradle-module validation (C): definitions from dependency JARs via hint functions
-
@Providedannotation: marks types as externally available, skips safety validation - Android framework whitelist:
Context,Activity,Application,Fragment,SavedStateHandle,WorkerParameters - Cross-module function hint metadata (C2): encode qualifier, scope, bindings in hint parameters
- Qualifier propagation:
@Named/@Qualifierviaqualifier_<name>orqualifierTypehint params - Scope propagation:
@Scope(MyScope::class)viascopehint parameter - Bindings propagation: return type supertypes via
binding0,binding1, ... hint params
- Qualifier propagation:
- DSL validation (B): validate
single<T>(),factory<T>()in hand-written modules - Call-site validation (A4): validates
get<T>(),inject<T>(),koinViewModel<T>()call sites with deferred cross-module hints - Cross-module custom qualifier discovery via qualifier hint functions
- See COMPILE_TIME_SAFETY.md for detailed design and implementation
Done:
- Package filtering: scan now matches both function's package and return type's package
Remaining for 1.0:
- Property validation (D):
@Property/@PropertyValuematching — see §2.7 -
@ScopeIdsupport — see §2.8 -
Scopeparameter injection — see §2.9
2.4 @Monitor Annotation Support ✅
Function interception for logging and performance capture:
-
@Monitorannotation on class or function - Generate wrapper code to intercept function calls
- Log function entry/exit with parameters
- Capture execution time and performance metrics
- Integration with Koin's logging/monitoring API
@Monitor
class MyService {
fun fetchData(): Data { ... } // Calls will be intercepted
}
// Or on specific functions
class MyService {
@Monitor
fun fetchData(): Data { ... } // Only this function intercepted
}
2.5 JSR-330 Compatibility Toggle
Allow enabling/disabling JSR-330 annotation support via Gradle property:
- Add
jsr330option tokoinCompiler { }DSL (default:true) - Pass option to compiler plugin via
CommandLineProcessor - Skip
jakarta.inject.*andjavax.inject.*annotation processing when disabled - Document in README
// build.gradle.kts
koinCompiler {
jsr330 = false // Disable jakarta.inject/javax.inject support
}
2.6 Prebuilt Module Index
Generate pre-populated HashMap for instant startup — see PREBUILT_INDEX.md.
- Design finalized (static KoinIndex, buildEntry, indexedModule)
- koin-core API additions (KoinIndex, buildEntry, indexedModule, loadIndex)
- Compiler: generate
buildKoinIndex { buildEntry(...) }instead ofmodule { buildSingle(...) } - Compiler: transform
startKoin<T>()to useloadIndex()/ map assignment - Unsafe DSL detection (hand-written lambdas → compiler error when
prebuiltIndex = true) -
prebuiltIndexGradle option (default:falsein 1.x,truein 2.x)
2.7 Property Validation (D): @Property/@PropertyValue Matching ✅
Validates that @Property("key") parameters have a corresponding @PropertyValue("key") default.
Emits a warning (not error) since properties can be set at runtime via properties().
-
PropertyValueRegistryalready collects@PropertyValue("key")registrations -
BindingRegistry.validatePropertyKeys(): warns for@Property("key")without matching@PropertyValue - Called from
CompileSafetyValidator.validate()after module validation - Box test:
property_value_ok— @PropertyValue matches @Property key
2.8 @ScopeId Parameter Support ✅
Supports @ScopeId annotation for injecting values from a named Koin scope.
Generates getScope("scopeId").get<T>(). Validation skips @ScopeId parameters.
-
KoinAnnotationFqNames.SCOPE_IDregistered -
QualifierExtractor.getScopeIdAnnotationName(): handles@ScopeId(MyScope::class)and@ScopeId(name = "id") -
ParameterAnalyzer: classifies asisScopeId = true -
KoinArgumentGenerator.createGetFromNamedScopeCall(): generatesscope.getScope("id").get<T>() -
Requirement.requiresValidation(): returns false forisScopeId - Box test:
scope_id_ok
@Factory
class ProfileService(@ScopeId(name = "user_session") val session: UserSession)
// Generates: ProfileService(scope.getScope("user_session").get<UserSession>())
2.9 Scope Parameter Injection ✅
Constructor parameters of type org.koin.core.scope.Scope are injected with the scope receiver itself.
Compile safety validation automatically skips Scope parameters (can't statically validate dynamic lookups).
-
KoinArgumentGenerator: detect param typeorg.koin.core.scope.Scope→ passscopeReceiverdirectly -
ParameterAnalyzer: detect Scope type → skip validation (treated as implicitly@Provided) - Add tests (
scope_param_okbox test)
@Scoped
class ScopedService(val scope: Scope) {
fun dynamicLookup() = scope.get<SomeDep>() // Not validated at compile time
}
Multi-Kotlin Version Compatibility (Deferred)
Current approach: Follow latest Kotlin versions and adapt as needed. No complex versioning scheme required.
Background: Kotlin compiler plugins are not binary compatible across minor versions. A plugin compiled with Kotlin 2.2.21 won't work with Kotlin 2.3.x. If needed in the future, version-aligned releases (0.1.0-kotlin-2.2.21) can be implemented.