JVM conformance
100%
Cases whose box() returns OK on krusty's bytecode. CI fails when any applicable JVM case stops passing.
Kotlin/JVM compiler · written in Rust
krusty is a native binary, written in Rust, that takes kotlinc's command-line flags and writes JVM .class files. Every change is diffed against the real kotlinc. It needs no JVM to run.
Early, and measured in the open. krusty takes Kotlin/JVM modules, Android ones included, from Gradle, Bazel or the command line. Under Gradle, a compilation it cannot take yet, such as one that needs Compose or Parcelize, stays on kotlinc, and the task log says why.

Kotlin 2.4.21 · as shown on the README badges
Master builds compile Kotlin's codegen/box test suite with krusty and with kotlinc 2.4.21, the newest supported release. A case passes when its box() function returnsOK. Cases the suite marks as not running on a target are left out of that target's figures.
100%
Cases whose box() returns OK on krusty's bytecode. CI fails when any applicable JVM case stops passing.
72.5%
A progress gauge, not a share of identical classes. Each class counts only its bytes before the first difference from kotlinc's, over the longer of the two files; a failing case counts zero. 100% means every class is identical.
58.2%
Native-applicable cases that compile against the Kotlin/Native stdlib, link, run and return OK.
1.5%
Classes identical to kotlinc's, whole file, across popular open-source projects built nightly with their own Gradle builds. All metrics
All metrics, per project and per Kotlin version, regenerated nightly. How each figure is counted: docs/TEST_HARNESS.md. Other suites (kotlinx.serialization, KSP and the rest) are correctness gates and count toward none of these figures.
Install
krusty and put it on your PATH.JAVA_HOME or -jdk-home <dir>).Usage
# compile a source tree to a class directory
krusty src/ -d out/
# or to a jar
krusty src/ -d mylib.jar -module-name mylib
# with a classpath
krusty -cp deps.jar:classes/ App.kt -d out/
# all options
krusty -helpGradle
The Gradle plugin's krustyVerify task compiles every Kotlin/JVM compilation with kotlinc, as your build does today, and with krusty beside it. Nothing you ship changes.
The report in build/reports/krusty-verify/ lists which compilations krusty handles and which it leaves to kotlinc and why, how many classes are byte-identical to kotlinc's and how the rest differ, and both compilers' compile time and krusty's peak memory.
The report has a button that opens a prefilled GitHub issue with totals and difference kinds, with compilation, class and member names masked. Masking follows rules and cannot promise to catch every name, so review the issue before you submit it. Sending it tells us what to fix next.
1. Unpack krusty-gradle-plugin-<version>.zip from the latest release under gradle/
// settings.gradle.kts
pluginManagement {
repositories {
maven { url = uri("gradle/krusty-gradle-plugin-<version>/repository") }
gradlePluginPortal()
mavenCentral()
}
}2. Apply it after your Kotlin or Android plugin
// build.gradle.kts
plugins {
kotlin("jvm") version "2.4.21"
id("dev.krustythecompiler") version "<version>"
}3. Compare, without changing your build
./gradlew krustyVerifySignature checks, Android, multiplatform and mirrors are covered in the Gradle guide.
Why krusty
On the command line, an unsupported flag or plugin is an error, never silently skipped. Under Gradle it is logged and that task stays on kotlinc.
Every change is compared with the real kotlinc's output, and every master build runs Kotlin's codegen/box suite.
The metrics page compares krusty's peak memory with kotlinc's on real open-source projects.
Checksums signed with the maintainer's OpenPGP key and GitHub build provenance on every release file. The Gradle plugin checks the signature before it runs a compiler.
The krusty-lsp language server, with a Zed extension.
Compatibility
krusty targets every Kotlin release in kotlin-versions. On the command line, anything not listed here fails the build with an error. The Gradle plugin reports it and leaves that compile task to kotlinc.
| Build system | Status | Details |
|---|---|---|
| Command line | Supported | kotlinc-compatible flags for the supported subset; output to a class directory or a jar. Compiler plugins come in through -Xplugin/-P/-Xcompiler-plugin as for kotlinc. |
| Gradle | Supported | id("dev.krustythecompiler") plugin, shipped as krusty-gradle-plugin-<version>.zip in each release. Replaces the Kotlin/JVM compile tasks of source sets and of Android variants (AGP 9's built-in Kotlin or kotlin("android")). Validated with Gradle 7.6.3, 8.14.3, 9.5.0 and 9.7.0. kotlin-dsl builds such as buildSrc and compile tasks outside a source set stay with kotlinc, logged per task. |
| Kotlin Toolchain (project.yaml/module.yaml) | Partial | krusty-toolchain, built from source, as a drop-in for JetBrains' kotlin command. JVM modules only; a module with Java sources, a compiler setting it does not pass yet or an artifact to download is refused by name. See docs/KOTLIN_TOOLCHAIN.md. |
| Kotlin Build Tools API | Partial | krusty-build-tools-<version>-kotlin-<kotlin>.jar in each release stands in for kotlin-build-tools-impl in a build tool that loads the API from a classpath. JVM toolchain and in-process execution only. See tools/krusty-build-tools. |
| Bazel | Supported | krusty_jvm_library rule from the krusty Bazel module each release publishes, with the release's compiler as a toolchain per host and a --persistent_worker. The worker accepts no compiler plugins. See tools/krusty-bazel. |
| Maven | Partial | Verification only: the krusty-maven-plugin verify goal compiles each compilation with krusty beside kotlinc's output and reports how krusty fares. kotlinc still builds what Maven ships. See tools/krusty-maven. |
krusty cannot run kotlinc's FIR/IR plugin jars. It reimplements the plugins below natively and selects them from the same jar and options kotlinc receives, so a build switches compilers without changing its plugin configuration.
| Plugin | Status | Details |
|---|---|---|
| kotlinx.serialization | Supported | Conformance is measured against the plugin's own box-test corpus. |
| all-open (plugin.allopen, plugin.spring, plugin.jpa) | Supported | Including the spring and jpa presets. |
| no-arg (plugin.noarg, plugin.jpa) | Partial | Including the jpa preset; invokeInitializers=true is not implemented. |
| sam-with-receiver | Supported | |
| KSP (KSP2) | Partial | Through a build system. Under Gradle, KSP's own kspKotlin task runs the processors and krusty compiles what they generate (Gradle 8 or newer). Under the Kotlin Toolchain, only generated classes and resources are picked up. The plain command line rejects KSP. |
| kapt | Partial | Under Gradle: kapt's own tasks run the annotation processors with kotlinc, then krusty compiles the module. kapt options on the command line fail with an error. |
| Compose, Parcelize, assignment and every other FIR/IR plugin | Not supported | The command line fails with an error. The Gradle plugin reports the plugin and leaves that compile task to kotlinc, so the build still succeeds. |
| Kotlin scripts (.kts) | Not supported |
Roadmap
krusty compiles plain Kotlin/JVM code today, through the build systems and with the compiler plugins above. Next:
Sponsor
krusty is an independent project. If it is useful to your team, please consider sponsoring its development.