JSON to Kotlin Data Class Converter

Paste JSON and get @Serializable Kotlin data classes for Android, Ktor or any Kotlin project. The sample never leaves your device while the classes are generated.

JSON → Kotlin

Input

Settings

History

Load from URL

Data classes for Android and Ktor

Kotlin projects decode JSON with typed data classes, and kotlinx.serialization is the multiplatform standard for it: it works on Android, the JVM, Kotlin/JS and Kotlin Native, and Ktor uses it out of the box. Writing the classes for a big response is repetitive. Paste a response body from your network inspector or API docs and get classes you can use immediately.

What gets generated

  • Every JSON object becomes a @Serializable data class with val properties, and nested objects become their own classes named after their key.
  • JSON numbers become Long (whole numbers) or Double (anything with a decimal point or exponent); strings, booleans and arrays become String, Boolean and List<T>.
  • Keys that are not idiomatic Kotlin names are converted to camelCase, and @SerialName("first-name") keeps the original key for decoding and encoding.
  • Objects inside one array are merged. A property missing from some items, or null in some, becomes nullable with a default: val nick: String? = null. Thanks to the default, decoding succeeds when the key is absent.
  • Values that are only ever null, and arrays that mix types such as [1, "a"], are typed as JsonElement. kotlinx.serialization cannot decode a plain union, so you inspect the element at run time instead of risking a crash.
  • A JSON array at the root produces typealias Root = List<RootElement>.

The file starts with the kotlinx imports and a usage comment: Json.decodeFromString<Root>(jsonString).

Root type name

The only option, Root type name (default Root), names the top-level class or type alias. It is converted to PascalCase, so api response becomes ApiResponse. Nested classes are named after their keys, and items of a plural key are singularised, so badges holds Badge objects.

Setup and tips

The classes need the serialization plugin and runtime: add kotlin("plugin.serialization") to your Gradle plugins and org.jetbrains.kotlinx:kotlinx-serialization-json to dependencies. Real APIs add fields over time, so create your decoder with Json { ignoreUnknownKeys = true } to avoid failures when they do.

Inference is based only on your sample. Values written exactly as a calendar date (2024-03-11) become java.time.LocalDate, and the file then includes a small LocalDateSerializer registered with @file:UseSerializers — a JVM and Android type, so replace it with kotlinx.datetime.LocalDate in multiplatform code. Full timestamps stay String, and repeated strings are not turned into enums. Integers beyond 2^53 are flagged, since the sample cannot be read exactly; Long covers up to 2^63. For Jackson- or Gson-based projects, the Java class generator produces annotated POJOs instead. Generation runs locally in this tab, and the Kotlin formatter can restyle the result.

Examples

Profile response for an Android app

snake_case keys become camelCase properties with @SerialName, and expires_at becomes a nullable JsonElement with a null default.

Input
{
  "user_id": 42,
  "display_name": "Ben Okafor",
  "avatar_url": "https://cdn.example.com/u/42.png",
  "followers": 1280,
  "settings": { "dark_mode": true, "language": "en" },
  "badges": [
    { "code": "early", "awarded_at": "2024-03-11" },
    { "code": "mod", "awarded_at": "2025-01-20", "expires_at": null }
  ]
}
Output
// Decode with kotlinx.serialization:
//   val data = Json.decodeFromString<Profile>(jsonString)

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*

@Serializable
data class Profile (
    @SerialName("user_id")
    val userID: Long,

    @SerialName("display_name")
    val displayName: String,

    @SerialName("avatar_url")
    val avatarURL: String,

    val followers: Long,
    val settings: Settings,
    val badges: List<Badge>
)

@Serializable
data class Badge (
    val code: String,

    @SerialName("awarded_at")
    val awardedAt: String,

    @SerialName("expires_at")
    val expiresAt: JsonElement? = null
)

@Serializable
data class Settings (
    @SerialName("dark_mode")
    val darkMode: Boolean,

    val language: String
)
Open this example in the tool

Array root with optional fields

The root becomes a List type alias, and due is a nullable LocalDate with a null default because only one item has it.

Input
[
  { "id": 1, "title": "Write release notes", "done": true },
  { "id": 2, "title": "Review pricing", "done": false, "due": "2026-10-01" }
]
Output
// Decode with kotlinx.serialization:
//   val data = Json.decodeFromString<Todos>(jsonString)

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*

typealias Todos = List<Todo>

@Serializable
data class Todo (
    val id: Long,
    val title: String,
    val done: Boolean,
    val due: String? = null
)
Open this example in the tool

Common errors and how to fix them

ErrorCauseFix
Object keys must be in double quotes: found …
Explained
The sample is a Kotlin or JavaScript map literal rather than JSON.Quote every key with double quotes.
Unexpected '<' where a value was expected
Explained
An HTML error page was pasted instead of the JSON response.Copy the actual response body from the network inspector.
Unexpected end of input
Explained
The response was truncated when copying, for example from a log line.Copy the complete JSON document.

Frequently asked questions

Does it support Moshi or Gson?

The annotations target kotlinx.serialization. For Moshi or Gson, replace @SerialName with @Json(name=…) or @SerializedName and drop @Serializable.

Why is a property typed JsonElement?

Its value was always null in the sample, or it mixed types. JsonElement decodes safely whatever arrives, and you can narrow it once you know the real type.

Why do nullable properties have = null?

The default lets kotlinx.serialization decode objects where the key is missing entirely, which is what made the property optional in the first place.

Is my JSON uploaded?

No. Inference and code generation run in your browser.

Related tools