A Maven plugin for running Kotlin Symbol Processing (KSP) on JVM projects.
This plugin integrates KSP (Kotlin Symbol Processing) into Maven builds, allowing you to process Kotlin source files with annotation processors that use the KSP API.
Check out the blog post.
- Maven 3.6.0 or higher
- JDK 11 or higher
- Kotlin 2.2.21 or a compatible version
- Dual Scope Processing: Separate goals for main sources (
process) and test sources (process-test) - Thread Safe: Fully supports Maven parallel builds (
mvn -T) - Scope-Aware Logging: Distinct log prefixes for main (
[ksp:main]) and test ([ksp:test]) processing - Incremental Compilation: Optional incremental processing support
- Automatic Configuration: Automatically detects Kotlin version, JVM target, and other settings from the project environment
- Flexible Configuration: Extensive configuration options for all KSP parameters
The plugin provides two goals:
process: Processes main sources in thegenerate-sourcesphaseprocess-test: Processes test sources in thegenerate-test-sourcesphase
Minimal setup for processing main sources only:
<build>
<plugins>
<plugin>
<groupId>me.kpavlov.ksp.maven</groupId>
<artifactId>ksp-maven-plugin</artifactId>
<version>[LATEST VERSION]</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
<!-- KSP processors are plugin dependencies, not project dependencies -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-ksp-processor</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.2.21</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
</plugin>
</plugins>
<sourceDirectory>src/main/kotlin</sourceDirectory>
</build>To process both main and test sources (recommended):
<build>
<plugins>
<plugin>
<groupId>me.kpavlov.ksp.maven</groupId>
<artifactId>ksp-maven-plugin</artifactId>
<version>[LATEST VERSION]</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-ksp-processor</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.2.21</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
<phase>test-compile</phase>
</execution>
</executions>
</plugin>
</plugins>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
</build>All available configuration options:
<plugin>
<groupId>me.kpavlov.ksp.maven</groupId>
<artifactId>ksp-maven-plugin</artifactId>
<version>[LATEST VERSION]</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Main source directory to process (default: ${project.build.sourceDirectory}) -->
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<!-- Additional source directories (default: none) -->
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/generated/kotlin</sourceDir>
</sourceDirs>
<!-- Output directory for generated Kotlin sources (default: ${project.build.directory}/generated-sources/ksp) -->
<kotlinOutputDir>${project.build.directory}/generated-sources/ksp</kotlinOutputDir>
<!-- Output directory for generated Java sources (default: ${project.build.directory}/generated-sources/ksp) -->
<javaOutputDir>${project.build.directory}/generated-sources/ksp</javaOutputDir>
<!-- Output directory for compiled classes (default: ${project.build.directory}/ksp-classes) -->
<classOutputDir>${project.build.directory}/ksp-classes</classOutputDir>
<!-- Output directory for resources (default: ${project.build.directory}/generated-resources/ksp) -->
<resourceOutputDir>${project.build.directory}/generated-resources/ksp</resourceOutputDir>
<!-- KSP output directory (default: ${project.build.directory}/ksp) -->
<kspOutputDir>${project.build.directory}/ksp</kspOutputDir>
<!-- Cache directory for incremental processing (default: ${project.build.directory}/ksp-cache) -->
<cachesDir>${project.build.directory}/ksp-cache</cachesDir>
<!-- Enable incremental processing (default: false) -->
<incremental>true</incremental>
<!-- Enable incremental compilation logging (default: false) -->
<incrementalLog>true</incrementalLog>
<!-- Kotlin language version (default: detected from kotlin-maven-plugin or kotlin.version) -->
<languageVersion>2.2</languageVersion>
<!-- Kotlin API version (default: detected from languageVersion) -->
<apiVersion>2.2</apiVersion>
<!-- JVM default mode for interfaces (default: detected from kotlin-maven-plugin or 'disable') -->
<jvmDefaultMode>disable</jvmDefaultMode>
<!-- KSP processor options as key-value pairs (default: none) -->
<apOptions>
<option1>value1</option1>
<option2>value2</option2>
</apOptions>
<!-- Continue build on processing errors (default: false) -->
<ignoreProcessingErrors>false</ignoreProcessingErrors>
<!-- Treat all warnings as errors (default: false) -->
<allWarningsAsErrors>false</allWarningsAsErrors>
<!-- Map annotation arguments in Java sources (default: true) -->
<mapAnnotationArgumentsInJava>true</mapAnnotationArgumentsInJava>
<!-- Module name (default: ${project.artifactId}) -->
<moduleName>my-module</moduleName>
<!-- JVM target version (default: detected from kotlin-maven-plugin or maven.compiler.release) -->
<jvmTarget>17</jvmTarget>
<!-- Skip KSP processing (default: false, can be set via -Dksp.skip=true) -->
<skip>false</skip>
<!-- Add generated sources to compilation (default: true) -->
<addGeneratedSourcesToCompile>true</addGeneratedSourcesToCompile>
<!-- Enable debug output (default: false) -->
<debug>false</debug>
</configuration>
<!-- KSP processors are plugin dependencies, not project dependencies -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-ksp-processor</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>The plugin automatically detects many settings from the project configuration and properties:
| Parameter | Detection Source (in order of priority) |
|---|---|
languageVersion |
<languageVersion> in kotlin-maven-plugin, kotlin.compiler.languageVersion property, or kotlin.version (major.minor) |
apiVersion |
<apiVersion> in kotlin-maven-plugin, kotlin.compiler.apiVersion property, or languageVersion |
jvmTarget |
<jvmTarget> in kotlin-maven-plugin, kotlin.compiler.jvmTarget, maven.compiler.release, or maven.compiler.target |
jdkHome |
<jdkHome> in kotlin-maven-plugin, kotlin.compiler.jdkHome, or java.home system property |
allWarningsAsErrors |
<allWarningsAsErrors> in kotlin-maven-plugin, or kotlin.compiler.allWarningsAsErrors property |
Many parameters can be set via command line or Maven properties:
ksp.skip: Skip KSP processing for main sources (-Dksp.skip=true)ksp.skipTest: Skip KSP processing for test sources (-Dksp.skipTest=true)ksp.debug: Enable debug output (-Dksp.debug=true)kotlin.compiler.languageVersion: Set Kotlin language versionkotlin.compiler.jvmTarget: Set JVM target version
The plugin uses different output directories for main and test processing:
- Kotlin/Java sources:
${project.build.directory}/generated-sources/ksp - Classes:
${project.build.directory}/ksp-classes - Resources:
${project.build.directory}/generated-resources/ksp - KSP working directory:
${project.build.directory}/ksp - Cache:
${project.build.directory}/ksp-cache
- Kotlin/Java sources:
${project.build.directory}/generated-test-sources/ksp - Classes:
${project.build.directory}/ksp-test-classes - Resources:
${project.build.directory}/generated-test-resources/ksp - KSP working directory:
${project.build.directory}/ksp-test - Cache:
${project.build.directory}/ksp-test-cache
All directories can be customized via configuration parameters.
The plugin integrates with Maven's standard lifecycle phases:
generate-sourcesphase: KSP processors run on main sources- Generated sources automatically added to compilation source roots
compilephase: Kotlin compiler compiles both original and generated sources
generate-test-sourcesphase: KSP processors run on test sources- Generated test sources automatically added to test compilation source roots
test-compilephase: Kotlin compiler compiles both original and generated test sources
The plugin is fully thread-safe and supports Maven's parallel build execution:
# Build with 4 parallel threads
mvn clean install -T4
# Build using 1 thread per CPU core
mvn clean install -T1CEach execution creates isolated instances of KotlinSymbolProcessing with no shared mutable state, ensuring safe concurrent builds in multi-module projects.
For detailed information about thread safety guarantees, see PARALLEL_EXECUTION.md.
Skip main source processing via command line:
mvn clean install -Dksp.skip=trueOr in your pom.xml:
<configuration>
<skip>true</skip>
</configuration>Skip test source processing via command line:
mvn clean test -Dksp.skipTest=trueOr in your pom.xml for the process-test execution:
<execution>
<id>process-test-sources</id>
<goals>
<goal>process-test</goal>
</goals>
<configuration>
<skipTest>true</skipTest>
</configuration>
</execution>If you see "No KSP processors found in dependencies":
- Verify your processor is added as a plugin dependency (inside
<plugin><dependencies>section), not as a project dependency - Check the processor JAR contains
META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider - Ensure the dependency scope is not
test
If the Kotlin compiler can't find generated sources:
- Verify
addGeneratedSourcesToCompileistrue(default) - Check that KSP plugin runs before Kotlin compilation
- Verify output directories are correct
If incremental compilation causes problems:
- Disable it:
<incremental>false</incremental> - Clean the cache:
mvn clean - Delete
${project.build.directory}/ksp-cache
Enable debug output to see detailed processing information:
<configuration>
<debug>true</debug>
</configuration>This will log:
- Found KSP processors
- Processor classloader details
- Processor providers
- KSP configuration
- Incremental changes (if enabled)
Log messages are prefixed with scope identifiers:
[ksp:main]for main source processing[ksp:test]for test source processing
Build, verify, install the plugin and test with sample project:
make buildFormat code:
make formatRun linting:
make lintGenerate API documentation:
make apidocsRun all checks (format, lint, build):
make allBuild and install the plugin:
mvn clean installTest with the sample project:
cd sample-project
mvn clean compileContributions are welcome! Please follow the Kotlin coding conventions and ensure all tests pass.