Moshi: Key Concepts, JSON Library for Kotlin and How It Works

Author: IT Sectr Published: 2026-03-15 Reading time: 8 min

Moshi is a modern JSON library from Square, created specifically for Kotlin and Android with Gson’s limitations in mind. It is fully compatible with Kotlin null safety, generates code at compile time, and does not use reflection, which improves performance and reliability. According to Square Moshi, 2024, Moshi provides predictable serialization and supports custom adapters for any data types.

Key Takeaways

  • Moshi — JSON library from Square for Kotlin and Android without reflection
  • Kotlin adapter — built-in support for data classes, default values, and null safety
  • @Json — annotation for configuring field names and ignoring properties
  • Adapters — custom serialization logic via @ToJson and @FromJson
  • Code generation — Moshi generates adapters at compile time through kapt or KSP

What is Moshi

Moshi is a JSON library for JVM, Android, and Kotlin Multiplatform, created by Square (the authors of OkHttp and Retrofit). Unlike Gson, Moshi does not rely on reflection — adapters are generated at compile time via the @JsonClass(generateAdapter = true) annotation. This makes Moshi faster, safer, and more predictable when working with Kotlin-specific constructs.

Philosophy and Advantages

The main difference between Moshi and its predecessors is the rejection of reflection. Reflection allows Gson to work with any class without preparation, but the cost is slow initialization, inability for compiler optimization, and the risk of runtime errors. Moshi requires explicit class declaration for code generation, but in return provides hand-written code speed and full type safety at compile time.

kotlin
// Add Moshi to build.gradle
dependencies {
    implementation "com.squareup.moshi:moshi:1.15.0"
    implementation "com.squareup.moshi:moshi-kotlin:1.15.0"
    kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
}

// Simple model with code generation
@JsonClass(generateAdapter = true)
data class User(
    @Json(name = "user_id")
    val id: Int,
    val name: String,
    val email: String,
    val avatar: String? = null
)

// Usage
val moshi = Moshi.Builder()
    .build()
val jsonAdapter = moshi.adapter(User::class.java)

Setup and Configuration

To start working with Moshi, you need to add dependencies to build.gradle and annotate the models. Moshi.Builder serves as the entry point: through it, built-in adapters for standard types, custom adapters are added, and the library's behavior is configured. Moshi supports adapters for Date, Enum, Collection, and Map out of the box, but Kotlin classes require the moshi-kotlin module. Unlike Gson, Moshi does not use reflection for Kotlin classes by default — for this, KotlinJsonAdapterFactory is connected, which serves as a fallback when code generation is not used or the class is not annotated with @JsonClass. This approach ensures that the developer explicitly chooses between code generation performance and reflection flexibility for each specific class.

Creating Moshi and Adding Adapters

After building Moshi through Builder, the developer gets a Moshi instance and requests an adapter for the desired class. JsonAdapter is the central object that performs serialization via toJson() and deserialization via fromJson(). Moshi automatically uses the generated adapter if the class is annotated with @JsonClass(generateAdapter = true), otherwise it applies the reflective KotlinJsonAdapterFactory as a fallback. This approach combines the speed of code generation with the flexibility of a reflective mechanism for projects of any scale and complexity. Moshi is well suited for both small applications and large enterprise projects with hundreds of data models.

kotlin
// Configure Moshi with KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .add(LocalDateAdapter())
    .build()

// Using the adapter
val adapter = moshi.adapter(User::class.java)

// Serialization
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)

// Deserialization
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)

// Working with lists
val listAdapter = moshi.adapter(
    Types.newParameterizedType(
        List::class.java,
        User::class.java
    )
)

Annotations and Adapters

Moshi uses annotations to configure serialization and support custom types. @Json(name = "...") sets the JSON key for a field. @Transient excludes a field from serialization. @JsonClass(generateAdapter = true) enables code generation. For custom logic, Moshi provides @ToJson and @FromJson annotations, which can be placed in a separate adapter class.

@Json and Custom Adapters

The @Json annotation replaces Gson’s @SerializedName and works similarly: the kotlinName field is mapped to the JSON key "kotlin_name". For types that Moshi cannot serialize by default (e.g., LocalDate), the developer creates a class with @ToJson and @FromJson methods. Adapters are registered via Moshi.Builder.add() and apply globally or to a specific type. Moshi supports sealed classes and polymorphic serialization via @JsonClass with an explicit discriminator, allowing type hierarchies in JSON without manual field checking. During deserialization, Moshi ignores unknown JSON keys by default, ensuring backward compatibility when adding new fields on the server side without changing client code. For debugging, strict mode can be enabled via failOnUnknown, which throws an exception when unknown keys are encountered.

kotlin
// Custom adapter for LocalDate
class LocalDateAdapter {

    @ToJson
    fun toJson(date: LocalDate): String {
        return date.format(DateTimeFormatter.ISO_LOCAL_DATE)
    }

    @FromJson
    fun fromJson(dateString: String): LocalDate {
        return LocalDate.parse(dateString)
    }
}

// Model with Moshi annotations
@JsonClass(generateAdapter = true)
data class Event(
    @Json(name = "event_id")
    val id: Int,

    @Json(name = "event_date")
    val date: LocalDate,

    @Transient
    val localCache: String? = null
)

// Register the adapter
val moshi = Moshi.Builder()
    .add(LocalDateAdapter())
    .add(KotlinJsonAdapterFactory())
    .build()

Moshi vs Gson

Comparing Moshi and Gson is a common question when choosing a JSON library for an Android project. Moshi wins in modern Kotlin development due to code generation, null safety, and speed. Gson remains relevant for Java projects, legacy code, and scenarios where minimal configuration is important. The difference becomes noticeable with large data volumes and complex models.

Performance and Safety

Performance tests show that Moshi with code generation is 2–5 times faster than Gson on serialization and deserialization operations. The key advantage of Moshi is correct handling of Kotlin null safety: if a field is missing in JSON and the model declares it as non-null without a default value, Moshi throws an exception at deserialization time, preventing hidden errors.

CharacteristicGsonMoshi
Mechanismreflectioncode generation / reflection
Null safetynot supportedfull Kotlin support
Speedaveragehigh
Default valuesnot supportedsupported
Kotlin Multiplatformnoyes
Library size~240 Kb~150 Kb

The choice between Moshi and Gson depends on the project context. New Kotlin projects benefit from Moshi thanks to type safety and performance. Gson remains a reasonable choice for supporting Java code, dynamic JSON structures, or when simplicity of setup matters more than speed. For Kotlin Multiplatform, Moshi is the only one of the two options that supports this platform.

When migrating from Gson to Moshi, the main changes concern annotations and adapters. Gson’s @SerializedName is replaced with @Json(name = "..."), and custom JsonSerializer/JsonDeserializer with the @ToJson/@FromJson pair. For models with default values and nullable fields, Moshi behaves more predictably: if a non-null field without a default is missing in JSON, Moshi throws JsonDataException, preventing hidden NPEs. Integration with Retrofit via MoshiConverterFactory is added with a single dependency and does not require changing the network layer architecture. For obfuscation via ProGuard or R8, you need to add rules to preserve @JsonClass-annotated classes and generated adapters, otherwise serialization will break in the release build. Overall, migrating from Gson to Moshi is justified in new Kotlin projects where performance and type safety are important.

kotlin
// Serialization comparison: Gson vs Moshi
data class Sample(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

// Gson: works through reflection
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
    Sample::class.java)
// count = 0 (default), but null safety is not checked

// Moshi: requires an adapter, null safety is explicit
@JsonClass(generateAdapter = true)
data class SampleMoshi(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

Frequently Asked Questions

What is Moshi in Android?

Moshi is a JSON library from Square for Kotlin and Android that uses code generation instead of reflection. It provides high performance, correct handling of Kotlin null safety, and compatibility with Kotlin Multiplatform.

How is Moshi better than Gson?

Moshi surpasses Gson in speed (2–5 times faster thanks to code generation), safety (respects Kotlin null annotations), and size (~90 Kb smaller). Moshi also supports Kotlin Multiplatform and default values in data classes.

How does the @JsonClass annotation work in Moshi?

@JsonClass(generateAdapter = true) instructs Moshi to generate an adapter for the given class at compile time. The generated adapter performs serialization directly, without reflection, providing maximum performance.

How to create a custom Moshi adapter?

Create a class with methods annotated with @ToJson (serialization) and @FromJson (deserialization). Register the instance via Moshi.Builder.add(). Moshi will automatically find and apply the adapter when working with the corresponding type.

Does Moshi support Kotlin Multiplatform?

Yes, Moshi supports Kotlin Multiplatform starting from version 1.13.0. This makes it the only popular JSON solution for KMP projects, allowing you to use common serialization code across all target platforms.

Summary

  • Moshi — a modern JSON library from Square with code generation instead of reflection
  • @JsonClass — annotation for adapter generation, providing hand-written code speed
  • @Json — JSON key configuration, @Transient — field exclusion from serialization
  • @ToJson and @FromJson — simple API for custom adapters of any type
  • Null safety — Moshi respects Kotlin annotations and throws an exception on mismatch
  • Performance — 2–5 times faster than Gson on serialization and deserialization operations
  • Kotlin Multiplatform — KMP support for universal serialization code

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also