Skip to content

Getting Started

Kraft is a Kotlin Symbol Processing (KSP) plugin that generates type-safe mapping functions between data classes at compile time. Instead of writing boilerplate conversion code by hand, you annotate your classes and Kraft generates extension functions for you.

Installation

Kraft requires Kotlin 2.0+ and KSP. Add the following to your build.gradle.kts:

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

dependencies {
    implementation("com.blu3berry.kraft:kraft-annotations:<version>")
    ksp("com.blu3berry.kraft:kraft-ksp:<version>")
}

For Kotlin Multiplatform projects:

kotlin {
    sourceSets {
        commonMain {
            // Make generated mappers visible to common source code
            kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin")
        }
        commonMain.dependencies {
            implementation("com.blu3berry.kraft:kraft-annotations:<version>")
        }
    }
}

// Add KSP for common main metadata:
dependencies {
    add("kspCommonMainMetadata", "com.blu3berry.kraft:kraft-ksp:<version>")
}

// Ensure KSP runs before compilation so generated code is available:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
    if (name != "kspCommonMainKotlinMetadata") {
        dependsOn("kspCommonMainKotlinMetadata")
    }
}

The kotlin.srcDir line adds the KSP output directory to your common source set so the IDE and all platform compilations can see the generated mappers. The dependsOn block ensures kspCommonMainKotlinMetadata runs before any Kotlin compilation task, so generated code is always up to date.

Your First Mapper

Define two data classes and a mapping config object:

import com.blu3berry.kraft.config.MapConfig

data class User(val name: String, val age: Int)
data class UserDto(val name: String, val age: Int)

@MapConfig(source = User::class, target = UserDto::class)
object UserMapper

Kraft generates an extension function on the source class:

// Generated by Kraft
fun User.toUserDto(): UserDto = UserDto(
    name = this.name,
    age = this.age,
)

You can then call it anywhere in your code:

val user = User(name = "Alice", age = 30)
val dto: UserDto = user.toUserDto()

Properties are matched by name. If the source and target have a property with the same name and the same type, it is mapped automatically -- no additional configuration needed.

Verifying Generated Code

Generated code appears in your build output directory:

  • JVM projects: build/generated/ksp/main/kotlin/
  • Kotlin Multiplatform: build/generated/ksp/metadata/commonMain/kotlin/

After building your project (./gradlew build or ./gradlew kspKotlin), you can inspect the generated files there. Your IDE should also index them automatically, making the generated extension functions available for autocompletion.

Three Ways to Declare Mappings

Kraft provides three annotation styles depending on where you want to place the mapping declaration:

Annotation Placed on Declares
@MapConfig(source = ..., target = ...) Standalone object External config, neither class is annotated
@MapFrom(Source::class) Target class "I am built from Source"
@MapTo(Target::class) Source class "I can be converted to Target"

All three generate the same extension function: fun Source.toTarget(): Target. Choose whichever fits your codebase conventions. The rest of this guide uses @MapConfig for most examples, but the concepts apply equally to @MapFrom and @MapTo.

Next Steps