Configure JSON Naming Strategy in Kotlin Serialization

Learn how to handle snake_case, camelCase, and kebab-case JSON keys with Kotlin's naming strategy options. Covers global strategies and per-field @SerialName overrides.

Serialization

Detailed Explanation

JSON Naming Strategies in Kotlin

JSON APIs commonly use snake_case while Kotlin uses camelCase. Instead of adding @SerialName to every property, you can configure a global naming strategy.

kotlinx.serialization Naming Strategy (1.6.0+)

val json = Json {
    namingStrategy = JsonNamingStrategy.SnakeCase
}

@Serializable
data class UserProfile(
    val userId: Int,          // maps to "user_id"
    val firstName: String,    // maps to "first_name"
    val lastName: String,     // maps to "last_name"
    val isActive: Boolean,    // maps to "is_active"
    val createdAt: String     // maps to "created_at"
)

How Snake Case Conversion Works

The strategy splits on camelCase boundaries and joins with underscores:

Kotlin property JSON key
userId user_id
firstName first_name
isActive is_active
apiURL api_u_r_l (careful!)

Overriding Individual Fields

Even with a global strategy, @SerialName takes precedence for specific fields:

val json = Json {
    namingStrategy = JsonNamingStrategy.SnakeCase
}

@Serializable
data class Config(
    val apiVersion: String,               // "api_version" (auto)
    @SerialName("APIKey") val apiKey: String  // "APIKey" (override)
)

Gson Naming Policy

val gson = GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create()

Moshi with KotlinJsonAdapterFactory

Moshi does not have a built-in naming strategy. Use @Json(name = "...") per field:

data class User(
    @Json(name = "user_id") val userId: Int,
    @Json(name = "first_name") val firstName: String
)

Which Approach to Choose?

Scenario Recommendation
All fields follow snake_case Global SnakeCase strategy
Mixed naming conventions Per-field @SerialName
Legacy API with inconsistencies Per-field annotations
Multi-platform project kotlinx.serialization global strategy

Common Pitfall: Acronyms

Consecutive uppercase letters can produce unexpected snake_case results. For properties like apiURL or htmlParser, test the output or use explicit @SerialName to avoid surprises.

Use Case

When migrating from a Python or Ruby backend to a Kotlin-based service, the JSON contracts use snake_case. A global naming strategy avoids hundreds of @SerialName annotations and keeps the Kotlin code idiomatic with camelCase properties.

Try It — JSON to Kotlin

Open full tool