skip to content

kotlinx.serialization Plugin

The serialization plugin generates a serializer for each @Serializable class at compile time, so no reflection is needed at runtime. That compile-time generation is also why it works on Native and JS, unlike reflection-based JSON libraries.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

How do you enable kotlinx.serialization in a Kotlin Gradle project, and what two pieces do you need besides the @Serializable annotation?

level: juniorimportance: must knowfreq 70%

answer

  1. plugin + runtime + annotation = 3 pieces
  2. plugin version tracks Kotlin version
  3. runtime version is independent
  4. kotlin("plugin.serialization")
  5. kotlinx-serialization-json dependency

basics

~10 s

Add the serialization compiler plugin in the Gradle plugins block and add the runtime library as a dependency. Then mark classes with @Serializable.

solid answer

~30 s

Two things beyond @Serializable: (1) apply the compiler plugin with `plugins { kotlin("plugin.serialization") version "..." }` (its version must track your Kotlin version), and (2) add a runtime dependency, typically `org.jetbrains.kotlinx:kotlinx-serialization-json`. The plugin generates the KSerializer code at compile time; the runtime provides the format (Json) and core classes the generated code calls into. With both in place you can do `Json.encodeToString(value)` and `Json.decodeFromString<T>(text)` on any @Serializable type. Without the plugin, @Serializable does nothing and you get a 'Serializer has not been found' or a compile error; without the runtime library, the generated code has nothing to link against.

code

kotlin · 11 lines
kotlin
plugins {
    kotlin("jvm") version "2.1.0"
    kotlin("plugin.serialization") version "2.1.0"
}

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

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

go deeper

for a junior

Knows you add a plugin block and a dependency and annotate with @Serializable; can copy a working setup.

for a middle

Explains the split between compiler plugin and runtime library and why both are needed; knows the encode/decode API.

for a senior

Articulates the version-coupling rule (plugin tracks Kotlin, runtime independent) and the failure modes for each missing piece.

for a principal

Reasons about supply-chain/version governance: pinning the plugin via the Kotlin version, managing format modules per-platform, and the compile-time-codegen tradeoff vs reflection libraries.

## What kotlinx.serialization is kotlinx.serialization is JetBrains' official, reflection-free serialization framework for Kotlin. It turns Kotlin objects into formats like JSON (and back) using code generated **at compile time**, not runtime reflection. ## The three required pieces 1. **The compiler plugin** — `kotlin("plugin.serialization")`. This is a Kotlin *compiler plugin* (not a library) that hooks into compilation and, for every class you annotate with `@Serializable`, synthesizes a `KSerializer<T>` implementation. 2. **The runtime library** — e.g. `kotlinx-serialization-json`. Provides `Json`, `KSerializer`, `SerialDescriptor`, encoder/decoder interfaces that the generated code calls. 3. **The `@Serializable` annotation** — marks which classes get a generated serializer. ## Gradle setup ```kotlin plugins { kotlin("jvm") version "2.1.0" kotlin("plugin.serialization") version "2.1.0" // match Kotlin version } dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") } ``` Key rule: the **plugin version must match the Kotlin compiler version**, because the plugin generates code against compiler internals. The **runtime library version is independent** and versions separately. ## Using it ```kotlin import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.encodeToString @Serializable data class User(val name: String, val age: Int) val json = Json.encodeToString(User("Ada", 36)) // {"name":"Ada","age":36} val back = Json.decodeFromString<User>(json) ``` ## Common failure modes - Forgot the plugin → `@Serializable` is inert; `Json.encodeToString` fails to resolve a serializer (a `SerializationException` or compile error). - Forgot the runtime → generated code references missing classes; build fails. - Version mismatch between plugin and Kotlin → plugin may not load or emit incompatible code.

  • Why must the plugin version match the Kotlin version but not the runtime library version?
    The compiler plugin generates code against compiler internals tied to a specific Kotlin release, so it ships per Kotlin version. The runtime library is ordinary bytecode the generated code calls, so it versions independently (e.g. 1.7.x) and is backward compatible across a range of Kotlin versions.
  • What happens at runtime if you apply the plugin but forget the json runtime dependency?
    It won't get to runtime — the build fails to compile/link because the generated serializer code references runtime classes (Json, KSerializer, encoders) that aren't on the classpath.

The plugin is the printing press (makes the serializer), the runtime is the ink and paper it prints on (Json, KSerializer); @Serializable is just the order to print this page.

saying these in an interview costs you the question

  • Thinking @Serializable alone is enough without applying the plugin
  • Believing kotlinx.serialization uses reflection like Jackson/Gson
  • Confusing the plugin (compiler) with the runtime library (jar)
  • Saying you add kotlinx-serialization-core but never the json/format module to actually serialize
  • Adding the plugin as a normal implementation dependency instead of in the plugins block

context

open as a page

What exactly does the kotlin-serialization compiler plugin generate for a @Serializable class, and why is 'no reflection' a key benefit?

level: middleimportance: must knowfreq 60%

basics

~20 s

For each @Serializable class the plugin generates the code that knows how to read and write that class's fields. Because the code is built at compile time, it doesn't inspect classes with reflection at runtime, so it's faster and works where reflection is limited.

open as a page

A teammate upgraded Kotlin but the build now fails serializing a class, or @Serializable seems ignored. How do you diagnose plugin/version issues with kotlinx.serialization?

level: middleimportance: should knowfreq 45%

basics

~10 s

Check that the serialization plugin version matches the new Kotlin version, that the plugin is actually applied, and that the runtime library is present. Mismatches or a missing plugin are the usual cause.

open as a page

Beyond @Serializable, which annotations does the serialization compiler plugin act on, and how do @SerialName, default values, and @Transient change the generated code?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The plugin reads annotations like @SerialName (rename a field or class), @Transient (skip a field), and @Required, plus default values, and bakes those rules into the generated serializer and its descriptor so encoding/decoding follow them.

open as a page

When would you choose the kotlinx.serialization compiler-plugin approach over a reflection-based library (Jackson/Gson), and what costs does compile-time codegen impose?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Choose kotlinx.serialization when you need Kotlin multiplatform, fast startup, and shrinker-friendly builds, or want first-class Kotlin support. The cost is more generated code, longer compiles, and a less mature ecosystem of format adapters than Jackson.

open as a page