
Compile-time aspect-oriented weaving via compiler IR transformation, injecting @Aspect/@Before advice with zero runtime overhead; supports suspend, inline, extension, expect/actual functions, inheritance, many-to-many targets, rich JoinPoint metadata.
Compile-time Aspect-Oriented Programming for Kotlin Multiplatform.
AspectK is a Kotlin compiler plugin that injects advice into your functions at compile time, using
the K2 IR transformation API. There is no runtime reflection and no proxy. Declare an @Aspect,
mark its advice with @Before, @After or @Around, and the calls are compiled into every function
that carries the target annotation.
[!WARNING] AspectK is in alpha. The API can change without notice between releases, and you may run into bugs. Pin the version you depend on and read the changelog before upgrading.
[!IMPORTANT] Use 0.4.2 or later. This is strongly recommended. It is the version validated on the DuckDuckGo Android browser.
// build.gradle.kts
plugins {
id("io.github.mole-labs.aspectk") version "LATEST_VERSION"
}For Kotlin Multiplatform:
plugins {
kotlin("multiplatform")
id("io.github.mole-labs.aspectk") version "LATEST_VERSION"
}@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class Loggedimport io.github.molelabs.aspectk.runtime.Aspect
import io.github.molelabs.aspectk.runtime.Before
import io.github.molelabs.aspectk.runtime.JoinPoint
@Aspect
object LoggingAspect {
@Before(target = [Logged::class])
fun log(joinPoint: JoinPoint) {
println("→ ${joinPoint.signature.methodName}(${joinPoint.args.joinToString()})")
}
}@Logged
fun processOrder(orderId: String, amount: Double) {
// AspectK injects LoggingAspect.log() here at compile time
}AspectK 0.4.2, resolved from Maven Central, was applied to
DuckDuckGo for Android: an open-source browser with
50M+ downloads on Google Play and 4.8k stars on GitHub. The whole change is public at
oungsi2000/Android (branch aspectk-trial).
| Project | DuckDuckGo Android 5.297.1: about 200 Gradle modules, 6,100+ Kotlin files, 900k+ lines |
| Applied to | 39 modules, 355 files changed |
| Aspects |
@OnIo (@Around, about 600 uses), @LogFailure on lambdas, @FireSavedSitesPixel, and @Before advice on the @WorkerThread, @UiThread and @MainThread annotations the code already carried |
| Unit tests | 28,749 passed, 0 failed: 22,297 in the library modules and 6,452 in :app
|
| R8 | the play APK builds minified with the project's internal release rules |
| Device | that minified APK was installed and run on a physical Android device |
AspectK is built with the help of AI tools, but it is not vibe-coded. The roles are split:
aspectk-core tests compile sources with the plugin and check the woven resultaspectk-core-tests (commonTest) run woven code on JVM, JS, Wasm and iOSaspectk-plugin functionalTest drives real Gradle builds, including incremental onessample tests build a multi-module app against the working tree, on JVM, Android, JS and iOS| Feature | Details |
|---|---|
| Compile-time injection | The generated code calls the advice function directly, with no reflection or proxy at runtime |
| Kotlin Multiplatform | JVM, Android, JS (IR), WASM/JS, Native Tier 1–3 |
| K2 IR | Built on the Kotlin 2.x IR transformation API |
@Before, @After, @Around |
Run code before a function, after it (like finally), or around it with control over the result |
| Many-to-many targeting | One advice can list several target annotations, and one function can match several aspects |
| Cross-module injection | An @Aspect in one module is injected into targets in a downstream module. Apply the plugin to both and nothing else is needed |
| Inheritance |
inherits = true also intercepts functions that override an annotated one |
| Join point metadata |
JoinPoint exposes the receiver, method signature, parameters, annotations and arguments |
Advice is injected during IR transformation, before any platform-specific lowering, so AspectK sees functions the way you wrote them:
suspend functions. Injection happens before coroutine lowering, so no continuation parameter shows up in args
inline functions. The advice is part of the body, so it is inlined along with itexpect/actual functions across all platformsJVM · Android · JS (IR) · WASM/JS · macOS (arm64, x64) · iOS (arm64, sim, x64) · Linux (arm64, x64) · Windows (x64) · watchOS · tvOS · Android Native
Full documentation: https://mole-labs.github.io/aspectk/
Copyright 2026 Mole Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Compile-time Aspect-Oriented Programming for Kotlin Multiplatform.
AspectK is a Kotlin compiler plugin that injects advice into your functions at compile time, using
the K2 IR transformation API. There is no runtime reflection and no proxy. Declare an @Aspect,
mark its advice with @Before, @After or @Around, and the calls are compiled into every function
that carries the target annotation.
[!WARNING] AspectK is in alpha. The API can change without notice between releases, and you may run into bugs. Pin the version you depend on and read the changelog before upgrading.
[!IMPORTANT] Use 0.4.2 or later. This is strongly recommended. It is the version validated on the DuckDuckGo Android browser.
// build.gradle.kts
plugins {
id("io.github.mole-labs.aspectk") version "LATEST_VERSION"
}For Kotlin Multiplatform:
plugins {
kotlin("multiplatform")
id("io.github.mole-labs.aspectk") version "LATEST_VERSION"
}@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class Loggedimport io.github.molelabs.aspectk.runtime.Aspect
import io.github.molelabs.aspectk.runtime.Before
import io.github.molelabs.aspectk.runtime.JoinPoint
@Aspect
object LoggingAspect {
@Before(target = [Logged::class])
fun log(joinPoint: JoinPoint) {
println("→ ${joinPoint.signature.methodName}(${joinPoint.args.joinToString()})")
}
}@Logged
fun processOrder(orderId: String, amount: Double) {
// AspectK injects LoggingAspect.log() here at compile time
}AspectK 0.4.2, resolved from Maven Central, was applied to
DuckDuckGo for Android: an open-source browser with
50M+ downloads on Google Play and 4.8k stars on GitHub. The whole change is public at
oungsi2000/Android (branch aspectk-trial).
| Project | DuckDuckGo Android 5.297.1: about 200 Gradle modules, 6,100+ Kotlin files, 900k+ lines |
| Applied to | 39 modules, 355 files changed |
| Aspects |
@OnIo (@Around, about 600 uses), @LogFailure on lambdas, @FireSavedSitesPixel, and @Before advice on the @WorkerThread, @UiThread and @MainThread annotations the code already carried |
| Unit tests | 28,749 passed, 0 failed: 22,297 in the library modules and 6,452 in :app
|
| R8 | the play APK builds minified with the project's internal release rules |
| Device | that minified APK was installed and run on a physical Android device |
AspectK is built with the help of AI tools, but it is not vibe-coded. The roles are split:
aspectk-core tests compile sources with the plugin and check the woven resultaspectk-core-tests (commonTest) run woven code on JVM, JS, Wasm and iOSaspectk-plugin functionalTest drives real Gradle builds, including incremental onessample tests build a multi-module app against the working tree, on JVM, Android, JS and iOS| Feature | Details |
|---|---|
| Compile-time injection | The generated code calls the advice function directly, with no reflection or proxy at runtime |
| Kotlin Multiplatform | JVM, Android, JS (IR), WASM/JS, Native Tier 1–3 |
| K2 IR | Built on the Kotlin 2.x IR transformation API |
@Before, @After, @Around |
Run code before a function, after it (like finally), or around it with control over the result |
| Many-to-many targeting | One advice can list several target annotations, and one function can match several aspects |
| Cross-module injection | An @Aspect in one module is injected into targets in a downstream module. Apply the plugin to both and nothing else is needed |
| Inheritance |
inherits = true also intercepts functions that override an annotated one |
| Join point metadata |
JoinPoint exposes the receiver, method signature, parameters, annotations and arguments |
Advice is injected during IR transformation, before any platform-specific lowering, so AspectK sees functions the way you wrote them:
suspend functions. Injection happens before coroutine lowering, so no continuation parameter shows up in args
inline functions. The advice is part of the body, so it is inlined along with itexpect/actual functions across all platformsJVM · Android · JS (IR) · WASM/JS · macOS (arm64, x64) · iOS (arm64, sim, x64) · Linux (arm64, x64) · Windows (x64) · watchOS · tvOS · Android Native
Full documentation: https://mole-labs.github.io/aspectk/
Copyright 2026 Mole Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0