skip to content

kapt (Legacy)

kapt runs Java annotation processors against Kotlin by first generating Java stubs, which works broadly but costs real build time. It is legacy now, and interviewers expect you to know why.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is kapt and what problem does the kotlin-kapt Gradle plugin solve for Kotlin projects?

level: juniorimportance: must knowfreq 60%

answer

  1. Kotlin Annotation Processing Tool
  2. Java stubs first, then process
  3. javax.annotation.processing.Processor
  4. kapt(...) configuration, kotlin-kapt plugin
  5. Bridge to Dagger/Room/Moshi

basics

~20 s

kapt is a Kotlin plugin that lets old Java annotation-processing tools (like Dagger or Room) work on Kotlin code. It does this by first turning Kotlin into simple Java placeholder files those tools can read.

solid answer

~40 s

kapt (Kotlin Annotation Processing Tool) is the `kotlin-kapt` Gradle plugin that runs standard Java `javax.annotation.processing.Processor` implementations against Kotlin sources. Java's `apt`/`Processor` API only understands Java type elements, not Kotlin, so kapt first generates Java **stubs** — empty-bodied Java declarations that mirror your Kotlin classes' signatures — then feeds those stubs to the annotation processors. Processors read annotations and emit generated code (e.g. Dagger's component classes, Room's DAO implementations). You apply the plugin and declare processors with the `kapt("...")` dependency configuration instead of `annotationProcessor`. It exists because, before KSP, the entire JVM annotation-processing ecosystem was Java-only and kapt was the bridge that made Dagger, Room, Moshi-codegen, etc. usable from Kotlin.

code

kotlin · 10 lines
kotlin
plugins {
    kotlin("jvm") version "2.1.0"
    kotlin("kapt") version "2.1.0"
}

dependencies {
    // Java annotation processor consumed via the kapt configuration
    kapt("com.google.dagger:dagger-compiler:2.51")
    implementation("com.google.dagger:dagger:2.51")
}

go deeper

for a junior

Knows kapt lets Java annotation processors work on Kotlin and is applied via the kotlin-kapt plugin.

for a middle

Explains the stub-generation step and the kapt(...) dependency configuration versus annotationProcessor(...).

for a senior

Frames kapt as the legacy bridge to the Java javax.annotation.processing ecosystem and can name the phases (stub gen, process, compile).

for a principal

Discusses why the design is inherently costly and positions kapt against KSP for ecosystem/migration decisions.

## What kapt is **kapt** stands for *Kotlin Annotation Processing Tool*. It is the `kotlin-kapt` Gradle plugin that allows **Java annotation processors** to run against Kotlin code. ## Background terms - **Annotation processor**: a compile-time plugin implementing `javax.annotation.processing.Processor` that reads annotations (e.g. `@Inject`, `@Entity`) and generates new source files. This is the `apt` mechanism built into `javac`. - **`javac`**: the Java compiler. Annotation processing is part of the Java compilation pipeline; processors see your code as Java **`Element`** objects (a `TypeElement` for a class, `ExecutableElement` for a method, etc.). - **The core problem**: that `Element` model only describes **Java** sources. The Kotlin compiler (`kotlinc`) is a separate compiler, so a Java processor cannot directly read Kotlin classes. ## How kapt bridges the gap — stub generation kapt works in phases: 1. **Stub generation**: kapt invokes the Kotlin compiler to produce **Java stub files** — `.java` files containing the public API surface (classes, method signatures, fields, annotations) of your Kotlin code but with **empty/placeholder method bodies** (typically `throw new RuntimeException("Stub!")`). These stubs are valid Java that `javac` and Java processors can read. 2. **Annotation processing**: kapt runs the registered Java processors over those stubs. Processors emit generated `.java` (and sometimes `.kt`) files. 3. **Compilation**: the generated sources plus your real Kotlin sources are compiled. ```kotlin // build.gradle.kts plugins { kotlin("jvm") version "2.1.0" kotlin("kapt") version "2.1.0" // applies the kotlin-kapt plugin } dependencies { kapt("com.google.dagger:dagger-compiler:2.51") // processor on the kapt classpath implementation("com.google.dagger:dagger:2.51") } ``` The `kapt("...")` configuration is the kapt equivalent of Java's `annotationProcessor("...")` configuration — it places the processor on the annotation-processing classpath. ## Why it matters Before **KSP** (Kotlin Symbol Processing), kapt was the *only* way to use the huge Java annotation-processing ecosystem — **Dagger/Hilt, Room, Moshi-codegen, AutoValue, Glide** — from Kotlin. It is now considered **legacy** because that stub-generation step is slow, but it remains widely used where no KSP processor exists. ## Key keywords - Plugin id: `kotlin-kapt` (DSL: `kotlin("kapt")`). - Dependency configuration: `kapt(...)`. - The defining mechanism: **Java stub generation** then standard `javax.annotation.processing`.

  • Why can't a Java annotation processor just read Kotlin classes directly?
    Java's annotation-processing API models code as Java `Element`s produced by `javac`. Kotlin is compiled by `kotlinc`, so there are no Java `Element`s for processors to inspect until kapt synthesizes Java stubs.
  • Which Gradle configuration adds a processor under kapt?
    The `kapt("group:artifact:version")` configuration, analogous to Java's `annotationProcessor(...)`.

kapt is a translator: Java processors only speak Java, so kapt writes a quick Java summary (stubs) of your Kotlin so the Java-only tools can read it.

saying these in an interview costs you the question

  • Claiming kapt is a separate compiler rather than a Gradle plugin around kotlinc + Java processing
  • Saying kapt runs Kotlin-native processors (those are KSP)
  • Not mentioning Java stub generation at all
  • Confusing kapt(...) with implementation(...) for the processor dependency

context

open as a page

Walk through configuring kapt for a Java annotation processor in a Gradle Kotlin DSL build, including how processor arguments are passed.

level: middleimportance: must knowfreq 50%

basics

~10 s

Apply the kotlin-kapt plugin, then add the processor with the kapt(...) line instead of implementation(...). If the processor needs options, pass them in a kapt { arguments { arg(...) } } block.

open as a page

Why is kapt's stub-generation step a performance concern, and what does it cost at the build level?

level: middleimportance: should knowfreq 55%

basics

~10 s

Before processing, kapt makes kotlinc produce extra Java placeholder files for your whole codebase. Generating those files runs an additional, expensive compilation pass, which makes builds noticeably slower.

open as a page

What does the kapt correctErrorTypes option do, and when do you need to enable it?

level: seniorimportance: should knowfreq 40%

basics

~20 s

correctErrorTypes tells kapt to recover the real types of code that is itself still being generated. Without it, those types show up as a meaningless 'error' placeholder and processors break. It is off by default.

open as a page

kapt is described as legacy. As a principal engineer, how would you decide whether and how to migrate a large multi-module project off kapt?

level: principalimportance: nice to knowfreq 30%

basics

~10 s

Check which of your annotation processors have a faster KSP version. Migrate those module-by-module, keep kapt only for the few processors that have no KSP option, and measure build-time improvement before and after.

open as a page