org.jetbrains.kotlin.plugin.serialization: Kotlin Serialization vs Gson and Other JSON Serialization Libraries

Development

Use Kotlin Serialization when your project is Kotlin-first, multiplatform, or strict about type safety. The plugin org.jetbrains.kotlin.plugin.serialization turns serialization into a compiler-backed feature instead of a runtime guessing game, which makes JSON handling cleaner, safer, and easier to refactor.

TLDR: Kotlin Serialization is usually the best choice for modern Kotlin apps because it understands Kotlin features like data classes, nullability, default values, and sealed classes. For example, a small Android team replacing Gson with Kotlin Serialization in a 40-model API layer may cut custom adapter code by roughly 30% to 50%, depending on how messy the API is. Gson is still fine for older Java-heavy codebases, while Moshi and Jackson remain strong in mixed stacks. If you are starting fresh with Kotlin, pick Kotlin Serialization first.

What the Kotlin Serialization plugin actually does

The Gradle plugin org.jetbrains.kotlin.plugin.serialization is not just a decorative add-on. It connects your Kotlin compiler to kotlinx.serialization, so serializers are generated at compile time. That means your app does not need to inspect classes through reflection every time it reads or writes JSON.

A typical setup looks like this:

plugins {
    kotlin("jvm") version "2.0.21"
    id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21"
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}

Then you mark your models:

@Serializable
data class User(
    val id: Long,
    val name: String,
    val premium: Boolean = false
)

That is the core appeal. No empty constructor tricks. No mysterious field injection. No runtime magic that breaks right after someone renames a property.

Kotlin Serialization vs Gson

Gson is popular because it is simple. For years, it was the default answer for Android JSON. Add a dependency, call Gson().fromJson(), and move on. That ease made it everywhere.

But Gson was built for Java. Kotlin came later. That history shows.

Honestly, it feels wrong that Gson can quietly put null into a non-null Kotlin property. The compiler tells you a value cannot be null, then runtime data says, “Actually, it can.” That kind of mismatch causes bugs that are annoying to trace because the model looks safe until it is not.

Gson also relies heavily on reflection. On Android, reflection can add startup cost and complicate shrinking rules. ProGuard and R8 can strip fields or constructors unless you add keep rules. Miss one rule and expect to waste time on a crash that only appears in release builds.

Kotlin Serialization avoids much of this. The compiler generates serializers. Kotlin rules matter. Defaults work as expected. Missing fields can fall back to default values. Non-null properties are treated with respect.

  • Gson: quick, old, Java-friendly, reflection-based.
  • Kotlin Serialization: Kotlin-aware, compiler-backed, safer with nullability and defaults.
  • Best Gson use case: legacy Java projects or apps already packed with Gson adapters.
  • Best Kotlin Serialization use case: new Kotlin apps, shared code, Android plus backend projects.

Kotlin Serialization vs Moshi

Moshi is a strong competitor. It was created by Square and has excellent Kotlin support when used with its Kotlin adapter or code generation. If you use Retrofit on Android, Moshi often feels natural.

Moshi is stricter than Gson and generally more pleasant in Kotlin projects. It handles nullability better. Its generated adapters avoid much of the reflection cost. Many teams moved from Gson to Moshi before Kotlin Serialization became mature.

So why choose Kotlin Serialization instead?

The main reason is platform reach. Kotlin Serialization works well across Kotlin/JVM, Kotlin/JS, Kotlin/Native, Android, and Kotlin Multiplatform. If your models live in a shared module used by Android and iOS, Kotlin Serialization fits neatly. Moshi is much more JVM-centered.

Kotlin Serialization also supports formats beyond JSON, including CBOR, ProtoBuf, and Properties. That can be useful when your app starts with JSON but later needs smaller payloads or binary formats.

Kotlin Serialization vs Jackson

Jackson is huge in backend Java. It is powerful, mature, and packed with features. Spring Boot users often already have it in the stack. It supports complex mappings, annotations, custom modules, streaming APIs, and many data formats.

That power comes with weight. Jackson can feel bulky for a small Kotlin app. You may need the Kotlin module, extra configuration, and several annotations to get behavior that feels basic in Kotlin Serialization.

For backend services with deep Java roots, Jackson still makes sense. It integrates well with established frameworks. If your team already has custom serializers and years of configuration, switching may not be worth the churn.

For a Kotlin service built from scratch, Kotlin Serialization is cleaner. The model classes stay focused. The compiler catches more errors. The dependency footprint is smaller.

Where Kotlin Serialization shines

Kotlin Serialization is especially good at representing Kotlin as Kotlin. That sounds obvious, but it matters every day.

  • Default values: Missing fields can use values from your constructor.
  • Null safety: Nullable and non-nullable properties are treated differently.
  • Sealed classes: Great for typed API responses and event models.
  • Multiplatform: Share models between Android, iOS, web, and server code.
  • No reflection requirement: Better fit for constrained runtimes and code shrinking.

For example, a sealed result type can model an API response with confidence:

@Serializable
sealed class PaymentResult {
    @Serializable
    data class Success(val receiptId: String) : PaymentResult()

    @Serializable
    data class Failure(val reason: String) : PaymentResult()
}

With Gson, sealed classes need extra work. With Kotlin Serialization, this style is expected.

Where Kotlin Serialization can annoy you

It is not perfect. The annotation requirement can feel repetitive. Every serializable class needs @Serializable, and third-party classes may need custom serializers.

The error messages are better than they used to be, but some still feel cryptic. A version mismatch between the Kotlin compiler, serialization plugin, and runtime library can produce errors that seem unrelated at first. It drives me crazy that one tiny version mismatch can turn a clean model into a confusing build failure.

Polymorphic serialization also requires care. If your API sends inconsistent type markers, you may need manual serializers or custom configuration. That is not unique to Kotlin Serialization, but the learning curve is real.

Performance and app size

Performance depends on models, payload size, device class, and configuration. Still, compiler-generated serializers usually perform well because they skip broad runtime inspection. On Android, the lack of reflection is a practical win.

For small JSON payloads, users may not feel a difference. Parsing a 2 KB response is rarely the bottleneck. For bigger payloads, repeated parsing, cold starts, or background sync jobs, the difference becomes more visible.

App size also matters. Gson is small, but reflection and keep rules can create maintenance cost. Jackson is larger. Moshi with code gen is efficient but adds annotation processing or KSP. Kotlin Serialization fits nicely when the compiler plugin is already part of the Kotlin build.

Which library should you choose?

  • Choose Kotlin Serialization for new Kotlin apps, Kotlin Multiplatform projects, strict models, and shared API contracts.
  • Choose Gson when maintaining older Java or Android code where Gson is already baked in and working.
  • Choose Moshi when you want a polished JVM/Android JSON library with strong Retrofit support.
  • Choose Jackson for enterprise backend systems, Spring-heavy services, and complex Java integrations.

If your team writes mostly Kotlin, org.jetbrains.kotlin.plugin.serialization is the cleanest long-term choice. It aligns with the language instead of working around it. Gson still has history on its side, Moshi has elegance, and Jackson has raw power. But Kotlin Serialization has the best fit when Kotlin is the center of the project.