Skip to content

Kotlin Multiplatform Serialization — Complete Guide

DodaTech Updated 2026-06-24 2 min read

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") in build.gradle.kts.
  • Annotate all serializable classes with @Serializable.
  • Use @SerialName for custom field mapping.
  • Use sealed classes with @SerialName for polymorphic types.
  • Use custom KSerializer for types that can't be annotated.

Common Mistakes with multiplatform serial

  1. Using return to exit a function early instead of wrapping a pure value in the monad
  2. Mixing let bindings with <- bindings in do notation, producing type errors
  3. 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

### Can I use Gson instead of kotlinx.serialization?

Yes, but only on JVM/Android. kotlinx.serialization is the recommended choice for KMP because it works on all platforms without reflection.

### How do I handle null fields?

Set encodeDefaults = true in the Json config to include nulls in output. Null fields are omitted by default unless explicitNulls = true.

### What is the @SerialName annotation?

It maps Kotlin property names to JSON field names. For example, @SerialName("email_address") on email produces {"email_address": "..."} instead of {"email": "..."}.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro