Kotlin Multiplatform Serialization — Complete Guide
In this tutorial, you'll learn about Kotlin Multiplatform Serialization. We cover key concepts, practical examples, and best practices.
The Problem
Your @Serializable data class throws SerializerNotFoundException, or polymorphic serialization doesn't work across platforms.
Wrong Approach ❌
// Not applying the serialization plugin
data class User(val id: String, val name: String) // No @Serializable
// Using Java serialization
class User : Serializable { // JVM-only!
// ...
}
Output: kotlinx.serialization.SerializationException or JVM-only code in commonMain.
Right Approach ✅
// build.gradle.kts
plugins {
kotlin("plugin.serialization")
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}
// commonMain
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(
val id: String,
val name: String,
@SerialName("email_address")
val email: String,
@Serializable(with = DateSerializer::class)
val createdAt: Long
)
@Serializable
data class ApiResponse<T>(
val success: Boolean,
val data: T // Polymorphic — requires context serializer
)
@Serializable
sealed class Status {
@Serializable
@SerialName("active")
data class Active(val since: Long) : Status()
@Serializable
@SerialName("inactive")
data class Inactive(val reason: String) : Status()
}
// Custom serializer
object DateSerializer : KSerializer<Long> {
override val descriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: Long) {
encoder.encodeLong(value)
}
override fun deserialize(decoder: Decoder): Long {
return decoder.decodeLong()
}
}
// Usage
val json = Json {
ignoreUnknownKeys = true
prettyPrint = true
encodeDefaults = true
classDiscriminator = "type" // For sealed class discrimination
}
fun serialize() {
val user = User("1", "Alice", "alice@example.com", System.currentTimeMillis())
val jsonString = json.encodeToString(user)
val decoded = json.decodeFromString<User>(jsonString)
// Polymorphic
val status: Status = Status.Active(System.currentTimeMillis())
val statusJson = json.encodeToString(status)
val statusDecoded = json.decodeFromString<Status>(statusJson)
}
Output: Cross-platform JSON serialization working on all targets.
Prevention
- Apply
kotlin("plugin.serialization")inbuild.gradle.kts. - Annotate all serializable classes with
@Serializable. - Use
@SerialNamefor custom field mapping. - Use sealed classes with
@SerialNamefor polymorphic types. - Use custom
KSerializerfor types that can't be annotated.
Common Mistakes with multiplatform serial
- Using
returnto exit a function early instead of wrapping a pure value in the monad - Mixing let bindings with <- bindings in do notation, producing type errors
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
These mistakes appear frequently in real-world KOTLIN code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro