skip to content

Despite KSP's advantages, when would you still be forced to use kapt, and how do you reason about that trade-off on a real project?

level: seniorimportance: nice to knowfreq 25%

answer

  1. kapt runs any javac processor unchanged
  2. KSP needs a SymbolProcessor port
  3. Forced to kapt = no KSP artifact
  4. Scope kapt to the one holdout dependency
  5. One kapt processor => stub generation stays

basics

~10 s

You must keep kapt when a library only provides an old Java-style annotation processor and no KSP version. kapt works with those because it runs the standard Java processing pipeline; KSP can't run them.

solid answer

~40 s

kapt's one durable advantage is **broad processor compatibility**: it runs any standard `javax.annotation.processing` (javac) processor unchanged, because it generates Java stubs and uses the Java APT pipeline. KSP only runs processors written against its own `SymbolProcessor` API. So you're forced onto kapt when a **required library ships only a javac processor** with no KSP artifact (legacy or unmaintained libraries are common cases). Reasoning on a real project: keep kapt **scoped to just that dependency**, migrate everything else to KSP to shrink the stub-generation cost, and track upstream KSP support. Accept that as long as one kapt processor remains, the kapt plugin and its stub round-trip stay in the build. Weigh whether to fork/replace the library, vendor a KSP alternative, or simply tolerate the slower path versus the migration cost.

go deeper

for a junior

Knows kapt is sometimes still needed for older libraries that don't support KSP.

for a middle

Explains kapt runs standard javac processors unmodified while KSP needs a ported processor.

for a senior

Scopes kapt to the holdout dependency, weighs replace/fork/tolerate, and knows one kapt processor keeps stub generation alive.

for a principal

Drives an organization-wide strategy: tracks ecosystem KSP readiness, prioritizes replacing kapt-only deps ahead of a KMP move, and quantifies build-time trade-offs.

## kapt's lasting edge: compatibility KSP is faster and multiplatform, but kapt has **one thing it does better: it runs the entire universe of existing javac annotation processors as-is.** Because kapt generates **Java stubs** and feeds them to the standard **`javax.annotation.processing`** pipeline inside **javac**, any processor ever written for Java 'just works' through kapt. KSP requires the processor to be **re-implemented against `SymbolProcessor`/`SymbolProcessorProvider`**. No KSP artifact ⇒ KSP can't run it. ## When you're forced to keep kapt - A **required library provides only a javac processor** and has not shipped a KSP version. - A library is **unmaintained / legacy** and never will. - An internal/in-house processor was written against the Java APT API and hasn't been ported. In all these cases, KSP is simply not an option for that dependency. ## Reasoning about the trade-off ```kotlin dependencies { // Migrated to KSP — fast path ksp("androidx.room:room-compiler:<v>") // Stuck on kapt — no KSP processor available kapt("com.legacy:old-processor:<v>") } ``` Decision factors: 1. **Scope kapt narrowly.** Migrate every KSP-capable processor; leave kapt only for the holdout. You still pay for stub generation, but you minimize how much work flows through it. 2. **Cost of removal vs. tolerance.** Is the build-time penalty meaningful at your scale? If the slow processor is small, tolerating kapt may beat the cost of replacing the library. 3. **Replace / fork / vendor.** For a critical hot path, consider swapping to a library with a KSP processor, or porting the processor. 4. **Track upstream.** Watch for the library shipping KSP support so you can finish the migration and delete kapt — which finally removes stub generation entirely. 5. **Multiplatform pressure.** If you intend to go KMP, a kapt-only dependency is a hard blocker for non-JVM targets, raising the priority of replacing it. ## Bottom line Use kapt when — and only when — a needed processor has no KSP implementation. Treat it as a contained, temporary cost: maximize KSP coverage elsewhere, and plan the exit when upstream KSP support lands or you replace the library.

  • If only one legacy library needs kapt, what's the cost to the rest of the build?
    The kapt plugin and its stub-generation pass remain active, so the whole module still pays the stub round-trip even though other processors run on KSP.
  • What makes a kapt-only dependency especially costly for a future KMP move?
    kapt is JVM-only, so a kapt-only library can't generate code for Native/JS targets at all, turning it into a hard blocker rather than just a slowdown.

saying these in an interview costs you the question

  • Claiming KSP can run any javac processor
  • Saying there's never a reason to keep kapt
  • Not realizing one kapt processor keeps stub generation
  • Ignoring fork/replace/vendor as options
  • Treating kapt removal as free regardless of library support

context