
Compile-time, type-safe object mapping via annotations; generated mappers return Result<T> with path-aware errors, compile-time lossless-conversion checks, fallback ladder, pluggable converters and observability.
Compile-time object mapping for Kotlin Multiplatform — annotate your wire models, get type-safe mappers generated by KSP. No reflection, no runtime registry, no boilerplate.
data class User(val id: Long, val joined: LocalDate)
@MapTo(User::class)
data class UserResponse(val id: Long, val joined: String)
// generated at compile time:
val user: Result<User> = UserResponse(7, "2026-06-12").toUserResult()What makes that different from every mapper you've hand-written:
Result<T> — malformed wire data is a
typed MappingException, never a surprise crash. The fallback ladder
(value > constructor default > null > error) keeps one bad field from destroying a
payload, and every absorbed error is reported to an observability sink.Cannot convert customer.address.zipCode: … — R8-safe, three
objects deep.Long → Int fails the build with a guiding message
instead of silently truncating in production.Full guide on GitBook: https://kmapper.gitbook.io/docs
Source Markdown in the repo: English · Türkçe — installation, the mental model, field mapping, null-safety, converters, validation, collections, enums, error handling, observability, multi-module setup, full annotation reference.
Prefer reading code? The sample gallery has 26 runnable examples
covering every feature, ordered basic → advanced (./gradlew sample:runSample).
Working on a project that uses KMapper? Start here:
kmapper.gitbook.io/docs/llms.txt.)@Ignore, @UseMapTypeConverter, @ValidateFrom/To,
@MapDefaultValue)? Those names still resolve but fail compilation with guided
ERROR-level deprecations naming the 2.0 replacement — follow the message or the
migration guide.plugins {
id("com.google.devtools.ksp") version "2.3.10-2.0.5"
}
dependencies {
implementation("io.github.sahsenvar:kmapper-core:2.2.2")
implementation("io.github.sahsenvar:kmapper-annotations:2.2.2")
ksp("io.github.sahsenvar:kmapper-compiler:2.2.2")
}KMP setup and add-ons: installation guide.
Group io.github.sahsenvar:
| Artifact | Platform | Purpose |
|---|---|---|
kmapper-core |
KMP | Standalone runtime: MappingException, converter base + 35 built-in pairs, validators, conversion seams, KMapper/MappingListener — usable without code generation |
kmapper-annotations |
KMP | Mapping declaration annotations (@MapTo/@MapFrom/@FieldMap/@ConvertWith/@Validate/…) |
kmapper-compiler |
JVM | KSP code generator (@MapTo/@MapFrom → toXResult() extensions) |
kmapper-converters-immutable |
KMP |
PersistentList/ImmutableList/PersistentSet/ImmutableSet wrappers |
kmapper-converters-arrow |
KMP |
NonEmptyList/NonEmptySet wrappers, Option<T> mapping |
kmapper-converters-datetime |
JVM/Android |
java.time converters (Instant, LocalDate, Duration, …) + kotlinx ↔ java bridges |
kmapper-converters-bignumber |
KMP (ionspin) / JVM+Android (java.math) |
String/Double/Long/Int ↔ BigDecimal/BigInteger; lossy directions refused at compile time |
kmapper-converters-uuid |
KMP / JVM+Android |
String ↔ kotlin.uuid.Uuid / java.util.UUID
|
kmapper-converters-okio |
KMP |
ByteString (UTF-8/Base64/Base64Url/Hex), Path
|
kmapper-converters-uri |
JVM / Android / iOS |
String ↔ java.net.URI / android.net.Uri / NSURL
|
kmapper-validators |
KMP | Email, URL, E.164 phone, IPv4/IPv6, hostname, UUID, slug, Base64/hex, geo, port, Luhn — for @Validate
|
kotlinx-datetime (LocalDate, Instant, …) and kotlin.time.Duration converters are
core built-ins — no add-on needed.
Latest release: 2.2.2 (11 artifacts) — on
Maven Central.
2.x is the converter-subsystem redesign; upgrading from 1.x?
Migration guide ·
CHANGELOG.
Design ledger & implementation plans live in docs/superpowers/ and
docs/converter-redesign.md.
Compile-time object mapping for Kotlin Multiplatform — annotate your wire models, get type-safe mappers generated by KSP. No reflection, no runtime registry, no boilerplate.
data class User(val id: Long, val joined: LocalDate)
@MapTo(User::class)
data class UserResponse(val id: Long, val joined: String)
// generated at compile time:
val user: Result<User> = UserResponse(7, "2026-06-12").toUserResult()What makes that different from every mapper you've hand-written:
Result<T> — malformed wire data is a
typed MappingException, never a surprise crash. The fallback ladder
(value > constructor default > null > error) keeps one bad field from destroying a
payload, and every absorbed error is reported to an observability sink.Cannot convert customer.address.zipCode: … — R8-safe, three
objects deep.Long → Int fails the build with a guiding message
instead of silently truncating in production.Full guide on GitBook: https://kmapper.gitbook.io/docs
Source Markdown in the repo: English · Türkçe — installation, the mental model, field mapping, null-safety, converters, validation, collections, enums, error handling, observability, multi-module setup, full annotation reference.
Prefer reading code? The sample gallery has 26 runnable examples
covering every feature, ordered basic → advanced (./gradlew sample:runSample).
Working on a project that uses KMapper? Start here:
kmapper.gitbook.io/docs/llms.txt.)@Ignore, @UseMapTypeConverter, @ValidateFrom/To,
@MapDefaultValue)? Those names still resolve but fail compilation with guided
ERROR-level deprecations naming the 2.0 replacement — follow the message or the
migration guide.plugins {
id("com.google.devtools.ksp") version "2.3.10-2.0.5"
}
dependencies {
implementation("io.github.sahsenvar:kmapper-core:2.2.2")
implementation("io.github.sahsenvar:kmapper-annotations:2.2.2")
ksp("io.github.sahsenvar:kmapper-compiler:2.2.2")
}KMP setup and add-ons: installation guide.
Group io.github.sahsenvar:
| Artifact | Platform | Purpose |
|---|---|---|
kmapper-core |
KMP | Standalone runtime: MappingException, converter base + 35 built-in pairs, validators, conversion seams, KMapper/MappingListener — usable without code generation |
kmapper-annotations |
KMP | Mapping declaration annotations (@MapTo/@MapFrom/@FieldMap/@ConvertWith/@Validate/…) |
kmapper-compiler |
JVM | KSP code generator (@MapTo/@MapFrom → toXResult() extensions) |
kmapper-converters-immutable |
KMP |
PersistentList/ImmutableList/PersistentSet/ImmutableSet wrappers |
kmapper-converters-arrow |
KMP |
NonEmptyList/NonEmptySet wrappers, Option<T> mapping |
kmapper-converters-datetime |
JVM/Android |
java.time converters (Instant, LocalDate, Duration, …) + kotlinx ↔ java bridges |
kmapper-converters-bignumber |
KMP (ionspin) / JVM+Android (java.math) |
String/Double/Long/Int ↔ BigDecimal/BigInteger; lossy directions refused at compile time |
kmapper-converters-uuid |
KMP / JVM+Android |
String ↔ kotlin.uuid.Uuid / java.util.UUID
|
kmapper-converters-okio |
KMP |
ByteString (UTF-8/Base64/Base64Url/Hex), Path
|
kmapper-converters-uri |
JVM / Android / iOS |
String ↔ java.net.URI / android.net.Uri / NSURL
|
kmapper-validators |
KMP | Email, URL, E.164 phone, IPv4/IPv6, hostname, UUID, slug, Base64/hex, geo, port, Luhn — for @Validate
|
kotlinx-datetime (LocalDate, Instant, …) and kotlin.time.Duration converters are
core built-ins — no add-on needed.
Latest release: 2.2.2 (11 artifacts) — on
Maven Central.
2.x is the converter-subsystem redesign; upgrading from 1.x?
Migration guide ·
CHANGELOG.
Design ledger & implementation plans live in docs/superpowers/ and
docs/converter-redesign.md.