You're migrating an Android module from kapt to KSP. Walk through the migration path and what determines whether you can migrate at all.
answer
- Migration is per library, not global
- Gate: does the lib ship a KSP processor?
- kapt(...) -> ksp(...) per dependency
- kapt + KSP can coexist during transition
- Remove kapt last => kills stub generation
basics
~20 sFirst check that each library you use offers a KSP version of its processor. If it does, swap the Gradle plugin and change kapt(...) to ksp(...) for that library. If a library only has a kapt processor, you must keep kapt for it.
solid answer
~40 sMigration is **per dependency**, gated by whether the library ships a **KSP-based processor**. Steps: (1) Apply the KSP Gradle plugin `id("com.google.devtools.ksp")` alongside (initially) the kapt plugin. (2) For each processor that supports KSP, change its dependency configuration from `kapt("…")` to `ksp("…")`. Many libraries publish a distinct KSP artifact (e.g. Room, Moshi codegen, Dagger/Hilt via KSP). (3) Re-sync/build; fix any generated-code or option differences (kapt and KSP arguments differ — e.g. `arg(...)` blocks). (4) Once **every** processor in the module is on KSP, **remove the kapt plugin entirely** to drop stub generation. The hard constraint: if any required processor has **no KSP implementation**, that library must stay on kapt, so the module keeps both plugins and you don't get the full speedup. You can run kapt and KSP simultaneously during a phased migration.
go deeper
Knows you swap kapt(...) for ksp(...) and add the KSP plugin, but may miss the per-library gating.
Articulates the per-dependency gate (KSP support), incremental migration, option reconciliation, and removing kapt last.
Plans a phased rollout, isolates failures per processor, aligns KSP/Kotlin versions, and reasons about partial-speedup states.
Owns a multi-module migration strategy, tracks ecosystem KSP readiness, and decides where kapt must remain versus blocking on upstream support.
## The core gating fact You cannot 'migrate kapt to KSP' as a blanket switch. KSP and kapt are different **processor APIs**. A processor must be **written against the KSP `SymbolProcessor` API** to run under KSP. So migration is **library-by-library**, and the question 'can I migrate?' reduces to 'does each library publish a KSP processor?' ## Step-by-step path ### 1. Add the KSP plugin ```kotlin plugins { id("com.android.library") kotlin("android") id("org.jetbrains.kotlin.kapt") // keep during transition id("com.google.devtools.ksp") // add KSP } ``` KSP's plugin version is aligned to your Kotlin version (e.g. `2.0.21-1.0.x`). ### 2. Move processors one at a time Swap the dependency **configuration** from `kapt` to `ksp`: ```kotlin dependencies { // before // kapt("androidx.room:room-compiler:<v>") // after ksp("androidx.room:room-compiler:<v>") implementation("androidx.room:room-runtime:<v>") } ``` Do this only for libraries that **document KSP support** (Room, Moshi codegen, Glide, Hilt/Dagger via their KSP path, etc.). Migrate and verify one at a time so failures are isolated. ### 3. Reconcile processor options kapt options set via `kapt { arguments { arg("key", "value") } }` become KSP options: ```kotlin ksp { arg("room.schemaLocation", "$projectDir/schemas") } ``` Generated output and edge cases (e.g. how nullability or default args are emitted) can differ slightly; rebuild and run tests. ### 4. Drop kapt when nothing needs it Once **all** processors are on KSP, remove the `kapt` plugin. Only then do you eliminate **stub generation** and realize the full build-time win. If even one library is kapt-only, you keep both plugins and pay for stubs. ## What blocks migration - **No KSP artifact** for a required library → must stay on kapt. - **Behavioral differences** in generated code → may need code changes or processor options. - **Version alignment** → KSP version must match the Kotlin compiler version. ## Phased / hybrid mode Running kapt and KSP **together** is fully supported and is the normal intermediate state during migration. The end goal is kapt removed, but partial migration still moves the migrated processors off the stub round-trip for their own work. ## Summary Apply the KSP plugin, flip `kapt(...)`→`ksp(...)` per supported library, reconcile options, then delete kapt when nothing depends on it. The ceiling is set entirely by library KSP availability.
- If you migrate 3 of 4 processors to KSP but one stays on kapt, do you get the full speedup?No. Because one processor still needs kapt, the kapt plugin stays and stub generation still runs, so you only get partial benefit.
- Where do kapt's processor arguments go in KSP?Into the ksp { } block via arg("key", "value"); kapt's kapt { arguments { arg(...) } } does not carry over automatically.
saying these in an interview costs you the question
- Believing a single Gradle flag converts all kapt to KSP
- Removing kapt while a kapt-only library remains
- Forgetting KSP version must match Kotlin version
- Not migrating/verifying processors incrementally
- Assuming generated code is byte-identical between kapt and KSP