CLI tool
google/ksp avatar
google/ksp

google/ksp: Kotlin Symbol Processing for compiler plugins

Kotlin Symbol Processing API

3,481 stars418 forksKotlinApache-2.0

At a glance

What is it?
KSP is Google's API for writing lightweight Kotlin compiler plugins, positioned against KAPT and documented mostly on kotlinlang.org rather than in the repository README. Here is how the Gradle configurations work, what a first processor looks like, and where the API stops being the right choice.
Who is it for?
Adopt google/ksp if you maintain a code generator, mapper or DI processor for Kotlin and want a Kotlin-native model of declarations instead of KAPT's Java view. Do not adopt it if your processor depends on Java annotation processing semantics, on javax.lang.model types, or on generating Java sources that a later Java compilation step must consume.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What problem google/ksp solves, and for whom

KSP is an API for developing lightweight compiler plugins. The README frames the trade-off directly: compared to KAPT, annotation processors that use KSP can run up to 2x faster. That number is the project's own claim, not a measurement reproduced here, and it is the reason most teams look at KSP in the first place.

The audience is narrow but deep. You are writing a symbol processor if you generate Kotlin or Java sources from annotated declarations: serialization adapters, dependency injection graphs, database accessors, mapping functions, builder types. You are not the audience if you only consume such libraries. In that case you add a dependency and the processor runs; the API surface described here is the library author's surface, and the day-to-day experience is a build configuration change rather than a coding task.

The second audience is build engineers who already ship a KAPT-based processor and are paying for it. KAPT runs annotation processing through a stub-generation step, so the processor sees Java stubs of Kotlin code rather than Kotlin declarations. KSP replaces that with an API that models Kotlin code directly, which is why the README points Java annotation processor authors at a dedicated reference page on kotlinlang.org. That page exists because the two models are not interchangeable, and the README assumes a reader who already knows one of them.

There is a third, smaller group: people who need to run symbol processing outside Gradle. The README links a command line page on kotlinlang.org, which suggests the framework can be driven directly, but the repository README itself documents only the Gradle path. Anyone scripting KSP in CI without Gradle is working from the kotlinlang.org page, not from this repository.

How the symbol processing model works

A KSP processor is a compiler plugin with a simplified API. The processor declares the annotation names it cares about, and the framework hands it symbols to resolve. The repository's top-level layout reflects this: symbol-processing/ holds the core, symbol-processing-aa-embeddable/ and kotlin-analysis-api/ sit alongside it, and api/ holds the published API surface. The cmdline-parser-gen/ directory and the docs/ directory are visible in the repository root listing.

The README links two behavioural notes that matter more than the API shape. Incremental processing notes describe how KSP decides which files to reprocess when inputs change; that decision is what keeps a large module from re-running every processor on every edit, and getting it wrong means either stale generated code or a full rebuild on every keystroke. Multiple round processing notes describe what happens when a processor generates code that itself contains annotations another processor handles. Both pages live on kotlinlang.org, so the README itself is not the reference for either, and a processor author who skips them will discover the rules by watching build output.

The examples/ directory contains hello-world/, multiplatform/ and playground/. Those three names map to the three situations a new processor author hits: a minimal single-platform processor, a processor that must resolve symbols across KMP source sets, and a sandbox for iterating on processor code without a full app build. The existence of a dedicated playground example is a signal about the workflow: processor development is iterative, and the repository expects you to have a fast loop rather than rebuild an application for each change.

The api/ directory being a top-level entry is worth noting. It implies the public surface is tracked separately from the implementation, which is the usual arrangement for a library that other projects compile against. For a processor author this means the API you write against is the one that gets reviewed for compatibility, and internals under symbol-processing/ are not part of that contract.

Installing KSP and wiring a first processor

The README does not carry install instructions. It points to the Quickstart on kotlinlang.org, and the Gradle configuration reference below is the part reproduced in the repository itself.

For a single-target JVM or Android project, the main source set uses the ksp configuration. The README's own usage example is a dependency line of this shape:

kotlin
ksp("com.example:processor:1.0")

Unit test sources use kspTest instead, and the README shows the same pattern with a test processor artifact. Android variants are addressed by name: kspDebug and kspRelease for build types, kspFree and kspPaid for flavors, and combinations such as kspFreeDebug for a specific flavor plus build type. Instrumentation tests use kspAndroidTestDebug, and local unit tests for a variant use kspTestDebug. Custom JVM source sets follow the same pattern, so a source set named integrationTest is addressed as kspIntegrationTest.

The README flags one trap. The plain ksp configuration is deprecated in Kotlin Multiplatform unless the property ksp.allow.all.target.configuration is set to true. In KMP, target-specific configurations are the supported route:

kotlin
add("kspJvm", "com.example:processor:1.0")
add("kspJs", "com.example:processor:1.0")
add("kspIosArm64", "com.example:processor:1.0")

The naming rule is easy to get wrong: the target configuration omits the Main suffix, so target jvm becomes kspJvm rather than kspJvmMain. Test compilations use kspJvmTest and kspJsTest. Common main metadata uses kspCommonMainMetadata, and the README also lists kspAndroidHostTest and kspAndroidDeviceTest as target names for Android targets in a multiplatform build.

If you are not using Gradle, the README links a command line page on kotlinlang.org. No command line invocation is reproduced in the repository README, so treat the Gradle path as the documented one and read the command line page before scripting KSP outside a build.

Where KSP is the wrong tool

KSP models Kotlin declarations, not Java ones. If your existing processor is built on javax.lang.model types and Java annotation processing semantics, porting it means rewriting the symbol traversal, not adjusting it. The README acknowledges this split by linking a reference specifically for Java annotation processor authors, which implies the mental model does not carry over unchanged. A processor that emits Java sources for a later Java compilation step is a particularly poor fit, because the whole point of the API is that the Kotlin compiler already holds the resolved types.

The deprecation of the plain ksp configuration in KMP is a second boundary. A processor published only for the ksp configuration will not resolve in a multiplatform build unless the project opts into ksp.allow.all.target.configuration. That property is a compatibility switch, and the README presents it as a condition rather than a recommendation. Treat it as a migration aid, not a target state.

Third, KSP is a plugin API, not a framework. It does not give you a runtime, a registry or a code generation DSL. If you want to generate code without writing a compiler plugin, a runtime reflection library or a code generation tool that runs as a normal Gradle task will be less work. KSP pays off when the generated code must be derived from the type graph the compiler already resolved, and stops paying off when the input is a schema file or a template that never needed type resolution.

Fourth, the repository README is thin. Most documentation, including incremental processing, multi-round behaviour and multiplatform guidance, lives on kotlinlang.org. Anyone who needs offline documentation or a pinned doc version should check the docs/ directory in the repository rather than assume the README covers it. Version skew between the README and the published docs is a real possibility when the README is a link list and the docs live elsewhere.

KSP compared with KAPT

KAPT is the direct alternative and the one the README names. KAPT runs Java annotation processors against generated Java stubs of your Kotlin code. The processor therefore works with Java types and Java element APIs, which is why a large body of existing processors runs under KAPT without modification. The cost is the stub generation step itself, which sits between your Kotlin sources and the processor and has to run before processing can begin.

KSP takes the opposite route. It exposes Kotlin symbols to a Kotlin API, so the processor sees Kotlin declarations with Kotlin nullability, Kotlin type parameters and Kotlin-specific constructs. The README states the payoff as performance: up to 2x faster than KAPT for processors that use it. The mechanism behind that number is the stub step KAPT requires and KSP does not, though the README does not spell out the measurement conditions, so treat the figure as directional rather than as a guarantee for a specific project.

The practical difference for a maintainer is migration cost. A KAPT processor that uses only standard annotation processing APIs can often be ported to KSP, but the port is a rewrite of the symbol handling, not a configuration change. Projects that maintain both usually publish two artifacts and keep the logic in a shared module, which doubles the release surface. If your processor must also run in a plain Java annotation processing environment, KSP alone will not cover that case, and the KAPT artifact has to stay.

A second alternative is not to write a processor at all. Kotlin compiler plugins at the full compiler API level offer more access than KSP, at a much higher cost in API stability and setup. KSP exists to sit between that and KAPT: less power than a raw compiler plugin, far less friction than one.

Maintenance, releases and licence

The repository is not archived, and the last push was on 2026-09-23. Releases are frequent: 2.3.12 on 2026-09-09, 2.3.11 on 2026-08-03 and 2.3.10 on 2026-07-09, based on the release list. The version numbers track the Kotlin version they target, which is the upgrade cost that matters most: a KSP release is tied to a Kotlin compiler version, so moving Kotlin means moving KSP in step, and skipping a Kotlin version usually means skipping the matching KSP release too.

That coupling is the main upgrade burden. A processor author has to test against each KSP release that matches a Kotlin release the project uses, and the multiplatform configurations mean a single processor may need artifacts for several targets. The repository contains integration-tests/ and test-utils/, and DEVELOPMENT.md covers debugging and testing processors as well as KSP itself, which is where to look before filing a bug against the framework. The benchmark/ directory is also present at the top level, so performance comparisons against KAPT have a home in the repository rather than only in the README claim.

KSP is licensed under Apache-2.0. That is a permissive licence, and it is the same licence family many Kotlin and Android libraries use, but the repository README does not discuss what it means for redistributing a processor or for generated code. Read the LICENSE file and, if generated output is shipped, get your own answer; this is not legal advice. CONTRIBUTING.md exists at the top level for anyone intending to send changes upstream.

The README also does not document a rollback path for a KSP upgrade, so pin the KSP version in your build and treat an upgrade as a change that needs its own verification pass rather than a routine dependency bump.

What to check before adopting google/ksp

Start with the version pairing. KSP releases carry Kotlin-aligned version numbers, so the first question is which KSP release matches the Kotlin version your build already uses. The release list in the repository is the source for that, and the README points to the Quickstart for the setup itself.

Next, check the configuration names against your project shape. A single-platform Android app uses ksp, kspTest and variant-specific names such as kspFreeDebug. A Kotlin Multiplatform library uses kspJvm, kspJs, kspIosArm64 and similar target names, plus kspCommonMainMetadata for common main. If your processor is published only for the ksp configuration, a KMP consumer cannot use it without ksp.allow.all.target.configuration, and the README marks that path as deprecated.

Then check the processor's own artifacts. The configuration reference lists test configurations separately, so a processor that does not publish a test artifact will not resolve under kspTest or kspJvmTest. The same applies to kspCommonMainMetadata: a processor that only ships a main artifact leaves common main source sets uncovered.

Finally, read the incremental and multi-round pages on kotlinlang.org before writing generation logic. Those two behaviours decide whether your processor rebuilds too much or loops on its own output, and neither is documented in the repository README. The examples/hello-world/ and examples/multiplatform/ directories are the fastest way to see a working configuration before you adapt it to your own module.

Editorial conclusion

Adopt google/ksp if you maintain a code generator, mapper or DI processor for Kotlin and want a Kotlin-native model of declarations instead of KAPT's Java view. Do not adopt it if your processor depends on Java annotation processing semantics, on javax.lang.model types, or on generating Java sources that a later Java compilation step must consume. Before committing, verify the KSP artifact version that matches your Kotlin version, and check whether your processors publish kspTest or kspCommonMainMetadata artifacts, because the configuration reference lists them separately and a processor that ships only a main artifact will not resolve in test or common source sets.

Frequently asked questions

What is google/ksp used for?

KSP is an API for developing lightweight compiler plugins, so it is used by library authors who generate code from annotated Kotlin declarations. The README positions it against KAPT, stating that processors using KSP can run up to 2x faster.

What is com.google.devtools.ksp?

It is the artifact namespace for KSP, the Kotlin Symbol Processing API published by Google under Apache-2.0. Processors and the Gradle plugin are added through the ksp configurations described in the README's Gradle reference.

Is google/ksp the same as KSP?

Yes. KSP stands for Kotlin Symbol Processing, and google/ksp is the repository that hosts it. The README describes it as an API for developing lightweight compiler plugins and links its documentation on kotlinlang.org.

How do I add a processor with google/ksp in a Gradle project?

Place the processor dependency in the configuration that matches your target and source set. For a single-target JVM or Android project the README shows ksp("com.example:processor:1.0") for main sources and kspTest for unit tests; Android variants use names such as kspDebug or kspFreeDebug.

Why is the plain ksp configuration deprecated in Kotlin Multiplatform?

The README states that ksp is deprecated in KMP unless the property ksp.allow.all.target.configuration is set to true. In multiplatform builds the supported route is target-specific configurations such as kspJvm, kspJs or kspIosArm64.

Official sources

  1. google/ksp on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/google-ksp.svg)](https://hysenlabs.com/projects/google-ksp)