What does @Transient do in kotlinx.serialization, and why must such a property have a default value?
answer
- Skips the property from the descriptor entirely
- Must have a default — plugin enforces it at compile time
- kotlinx.serialization.Transient, not the JVM one
- Never encoded, never decoded
- For caches/derived/secret fields
basics
~20 s@Transient tells the serializer to skip a property entirely: it is not written to JSON and not read from it. Because it is never decoded, it must have a default value so an object can still be constructed.
solid answer
~40 skotlinx.serialization's @Transient (from kotlinx.serialization, NOT java.beans.Transient) excludes a property from the serial descriptor. It is never encoded and never decoded — its serial form simply doesn't exist. Therefore it must declare a default value (= ...), because during decoding the serializer has no source for it and must initialize it from the default. The compiler plugin enforces this: a @Transient property without a default is a compile error. Typical uses: derived/computed state, caches, lazily-built fields, or values you never want on the wire (secrets). It differs from making a property non-@Serializable: @Transient is the explicit, intentional 'skip me' marker. Note it only affects properties declared in the body or constructor of a @Serializable class; the plugin only serializes properties anyway, and @Transient additionally drops constructor properties from the descriptor.
code
kotlin · 8 lines@Serializable
data class Cart(
val items: List<String>,
@Transient val computedTotalCache: Int = 0, // skipped, needs default
)
Json.encodeToString(Cart(listOf("a")))
// {"items":["a"]}go deeper
Knows @Transient hides a property from JSON.
Explains the mandatory default and that it is excluded from both encode and decode across all formats.
Distinguishes it from backing-field-less properties, contrasts with @Required, and cites the plugin's compile-time enforcement.
Discusses modeling derived/secret state, payload-contract implications, and the danger of confusing it with JVM transient in mixed serialization stacks.
## What @Transient means here `@Transient` (the one in `kotlinx.serialization`, **not** `java.io.Serializable`/`@java.beans.Transient`) marks a property of a `@Serializable` class as **excluded from serialization**. It is left out of the **serial descriptor**, so: - it is **never written** during encoding, and - it is **never read** during decoding (the encoded form contains nothing for it). ```kotlin import kotlinx.serialization.* @Serializable data class Session( val token: String, @Transient val decodedAt: Long = System.currentTimeMillis(), // skipped ) ``` Encoding `Session("abc")` yields `{"token":"abc"}` — `decodedAt` is absent. ## Why a default is mandatory When decoding, the serializer reconstructs the object but has **no value** for a transient property (nothing was on the wire). It therefore needs a value to put there. Kotlin's answer is the property's **default value**. The serialization **compiler plugin enforces** this: ```kotlin @Serializable class Bad(@Transient val cache: Map<String, Int>) // COMPILE ERROR // "This property is marked as @Transient and therefore must have a default value" ``` Add `= emptyMap()` and it compiles. The default is what every decoded instance receives. ## When to use it - **Derived/computed state** you can recompute (`val fullName get() = ...` — though computed `get()`-only properties are already not serialized; `@Transient` is for stored properties). - **Caches / lazies / timestamps** that shouldn't travel. - **Secrets** you must keep out of the payload. ## @Transient vs other ways to skip - A property with **no backing field** (an expression body `val x get() = a + b`) is **not** serialized at all — `@Transient` is unnecessary and actually not allowed there. - `@Transient` is for **stored** properties (constructor params or `val/var` with backing fields) you want to drop. - It is the opposite of `@Required`: `@Transient` removes a property; `@Required` forbids omitting one. ## Gotchas - Do not confuse it with the JVM `transient` keyword or `java.io.Serializable` — kotlinx.serialization has **its own** annotation. - A `@Transient` property cannot also be `@Required` or `@SerialName`-renamed meaningfully — it has no serial presence.
- What happens if you put @Transient on a property with no default value?It is a compile-time error from the serialization plugin: a transient property must have a default.
- Is an expression-body val (val x get() = a + b) serialized, and should you annotate it @Transient?It has no backing field so it is not serialized anyway; @Transient is unnecessary and not applicable there.
Like marking a line in a form 'office use only' — it never appears on the printed copy you exchange, so it always starts from a preset value.
saying these in an interview costs you the question
- Confusing kotlinx @Transient with java.io transient / @java.beans.Transient
- Saying a transient property can omit a default value
- Claiming it is still decoded but just not encoded
- Putting @Transient on a computed get()-only property
- Thinking @Transient only hides from JSON but keeps it in CBOR/ProtoBuf