JSON to Scala Case Class

Convert JSON to Scala 3 case classes with circe, play-json or upickle codecs

A free JSON to Scala converter: paste JSON and get Scala 3 case classes back instantly, each with its codec in the companion object. Pick the JSON library the codecs are written for: circe (Decoder and Encoder), play-json (Reads and Writes through a Format) or upickle (a ReadWriter over ujson.Value). Field types are inferred from the data (Int, Long, Double, Boolean, String, List and Option), nested objects become their own case classes, and keys that can be null or missing become Option fields that default to None. Names Scala reserves are renamed or put in backticks so the file compiles without warnings. Conversion runs entirely in your browser, so your JSON is never uploaded to a server.

Options on this page

Output format: Case class — Immutable case class with a codec in its companion.

OptionWhat it does
Root Class NameNames the top-level Case class.
Package (optional)Emitted as a package clause at the top of each file.
Field Naming ConventionOne of camelCase, PascalCase, snake_case, Preserve Original. Defaults to camelCase.
Type for null valuesEither Json (JsValue / ujson.Value) or String, used when a key is null in every sample.
Separate ClassesWrite each class to its own .scala file. Off (the default) puts every class in one file, so Copy All pastes into a single file that compiles.
Map original JSON keysRead and write each field under the original JSON key (a @key annotation for upickle). Without it a field only binds to a key spelled exactly like it, so a snake_case key is not read into a camelCase field.
JSON libraryOne of circe, play-json or upickle; picks which JSON library the generated code is written for.

How JSON values map to Scala types

JSON valueScala type
stringString
integerInt
integer beyond 32 bitsLong
decimalDouble
true / falseBoolean
ISO-8601 timestampString
arrayList[T]
objectnested case class
null or missing in some samplesOption[T] = None
nullJson / JsValue / ujson.Value (configurable)

Example

Input JSON

{
  "id": 1,
  "product_name": "Wireless Mouse",
  "tags": ["electronics"]
}

Generated Scala

final case class Product(id: Int, productName: String, tags: List[String])

object Product {
  given Decoder[Product] = Decoder.instance { c =>
    for {
      v0 <- c.get[Int]("id")
      v1 <- c.get[String]("product_name")
      v2 <- c.get[List[String]]("tags")
    } yield Product(v0, v1, v2)
  }

  given Encoder[Product] = Encoder.instance { x =>
    Json.obj(
      "id" -> Encoder[Int].apply(x.id),
      "product_name" -> Encoder[String].apply(x.productName),
      "tags" -> Encoder[List[String]].apply(x.tags)
    )
  }
}

Frequently asked questions

How do I convert JSON to a Scala case class?

Paste your JSON into the input pane and the Scala case classes appear beside it immediately. Set the root class name and an optional package, pick the JSON library, then copy the code or download it. With circe, parse the text and call .as[Root]; with play-json, Json.parse(text).as[Root]; with upickle, read[Root](text). Nested JSON objects become their own case classes and arrays become List[T].

Which JSON library should I choose?

circe is the most widely used in typed functional Scala and gives precise decoding errors; play-json is the usual pick in Play applications; upickle is small and fast and common in scripts and Scala.js. Each class carries a hand-written codec in its companion object, so no macro derivation or implicit configuration is involved and there is no limit on the number of fields. The case classes are the same for all three apart from the codec.

Why do some fields end in = None?

A key that is null or missing in at least one sample becomes an Option field that defaults to None, so a payload that omits it still decodes. A plain field makes the decoder fail when the key is absent.

Why are the codecs written by hand instead of derived?

Derivation needs a macro (circe-generic, Json.format, upickle macroRW), and those cannot rename a key per field without extra configuration or cannot expand a class with more than a couple of dozen fields; upickle fails to compile one at about 25 fields. A hand-written codec in the companion is a few lines per field, compiles at any size, and makes the key each field reads and writes explicit.

What happens to keys that are Scala keywords?

A field named class, type or val is written in backticks (`class`), which is how Scala spells a reserved word as a name. Names that would clash with a member every case class has, such as hashCode or copy, get a Value suffix. The JSON key is kept: with Map original JSON keys on, the codec reads and writes the original key.

Why are timestamps a String?

No date type round-trips every timestamp through all three libraries: java.time reformats the fractional digits and the zone when it writes a value back. A String always round-trips exactly; parse it with java.time where you need a date.

Is my JSON uploaded anywhere?

No. Parsing, type inference, and code generation all run in your browser using JavaScript. Your JSON is never sent to a remote server, and there is no account to create. The page keeps your last input and settings in your own browser (localStorage) so they survive a reload; nothing is stored anywhere else.

Is it safe to paste confidential JSON, such as API responses or customer data?

The conversion itself never transmits your JSON, so a confidential payload does not leave your machine. You can verify this: open your browser DevTools, switch to the Network tab, and convert something — no request carries your data. Two things to know: your last input is saved in your browser's localStorage (clear site data to remove it), and the Copy Link button embeds your JSON in the link, so anyone who opens that link, and the server that receives the request, can see it. Only share such links where you are comfortable with that.

Does it cost anything?

No. The generator is free to use with no sign-up and no usage limits.

How are nested objects handled?

Each nested JSON object becomes its own named type, derived from the key it appeared under. Arrays of objects are widened across every element, so a field that is a whole number in one element and a fraction in another gets a type that holds both.

Other languages

More JSON tools