๐Ÿ˜ธ kt-schema

KSP Processor Configuration

Table of contents

Generate JSON schemas at compile time with zero runtime overhead using the kt-schema KSP processor.

Setup

Configure the KSP processor with the Google KSP Gradle plugin.

Google KSP gradle plugin

Add the Google KSP plugin (2.3.1 or newer) and processor dependency to your project.

Multiplatform projects

kotlin
plugins {
    kotlin("multiplatform")
    id("com.google.devtools.ksp") version "<ksp-version>"
}

dependencies {
    add("kspCommonMainMetadata", "me.kpavlov.kt.schema:kt-schema-ksp:<version>")
    implementation("me.kpavlov.kt.schema:kt-schema-annotations:<version>")
}

kotlin {
    sourceSets.commonMain.kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin")
}

// Ensure KSP runs before compilation
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>().all {
    if (name != "kspCommonMainKotlinMetadata") dependsOn("kspCommonMainKotlinMetadata")
}

ksp {
    arg("me.kpavlov.kt.schema.rootPackage", "com.example")
}

Check out an example project .

JVM-only projects

kotlin
plugins {
    kotlin("jvm")
    id("com.google.devtools.ksp") version "<ksp-version>"
}

dependencies {
    ksp("me.kpavlov.kt.schema:kt-schema-ksp:<version>")
    implementation("me.kpavlov.kt.schema:kt-schema-annotations:<version>")
}

sourceSets.main.kotlin.srcDir("build/generated/ksp/main/kotlin")

Configuration options

Options can be set globally in your build configuration or overridden per-class via @Schema.

Options reference

OptionTypeDefaultDescription
enabledBooleantrueEnable or disable schema generation.
rootPackageStringnullLimit processing to this package and its subpackages. Improves build performance.
includeStringnullComma- or semicolon-separated glob patterns. Only matching symbols are processed.
excludeStringnullComma- or semicolon-separated glob patterns. Matching symbols are always skipped.
withSchemaObjectBooleanfalseGenerate jsonSchema: JsonObject property. Requires kotlinx-serialization-json.
visibilityString""Visibility modifier for generated extensions (public, internal, etc.).
configStringnullSchema flavour: strict, lenient, openapi or a JsonSchemaConfig class name. Unset: classes use strict, functions use the function-calling default. See Schema configuration .

Filtering by class/function name

Use me.kpavlov.kt.schema.include and me.kpavlov.kt.schema.exclude to control exactly which annotated classes and functions get schemas generated โ€” without touching the annotations themselves. Both options accept a comma- or semicolon-separated list of glob patterns matched against the fully qualified name.

Glob syntax:

PatternMatches
*Any sequence of characters within a single package segment (no .)
**Any sequence of characters across package segments (including .)
?Any single character (no .)

Rules:

Google KSP plugin

kotlin
ksp {
    arg("me.kpavlov.kt.schema.include", "com.example.api.**, com.example.dto.**")
    arg("me.kpavlov.kt.schema.exclude", "**.internal.**, **.*Internal")
}
tip

For large projects, combine rootPackage with include for maximum build performance: rootPackage narrows the KSP symbol scan, then include filters the remaining candidates.

Option priority

  1. Annotation Parameter (highest) โ€” @Schema(withSchemaObject = true)
  2. KSP Argument โ€” Global processor options passed through the Gradle ksp { arg(...) } block
  3. Default Value (lowest)
tip

Use an empty string visibility.set("") (default) for Multiplatform projects targeting Native to avoid “redundant visibility modifier” warnings.

Generated Code

For each @Schema-annotated class, the processor generates extension properties:

kotlin
@Schema(withSchemaObject = true)
data class User(val name: String)

Access generated extensions

kotlin
val jsonString: String = User::class.jsonSchemaString
val jsonObject: JsonObject = User::class.jsonSchema

For each @Schema-annotated function, the processor generates additional top-level or extension function:

kotlin
@Schema(withSchemaObject = true)
internal fun calculateArea(shape: Shape): Double = TODO("only signature matters")

Access generated functions:

kotlin
val functionCallSchemaString: String = calculateAreaJsonSchemaString() // <function name> + "jsonSchemaString()" 
val functionCallSchema: JsonObject = calculateAreaJsonSchema() // <function name> + "jsonSchema()" 

A parameter with a Kotlin default value (e.g. unit: String = "celsius") is optional: with the lenient, openapi or a custom non-strict config it is left out of required. The default strict config requires every parameter, as OpenAI strict mode demands. KSP reports only that a default exists, not its value, so no default is emitted.

Jakarta Bean Validation annotations on properties and function parameters (@Min(1) quantity: Int) become JSON Schema keywords. See the Validation Constraints guide .

See Also