NV ToolkitFormat · Validate · Convert

Code Generators

JSON to Crystal Converter

Paste a JSON or XML sample — the format is auto-detected — and get typed Crystal models with names, nesting and nullability inferred for you.

In short

Convert JSON to Crystal online: paste a sample and generate typed Crystal models with serialization helpers — powered by quicktype, in your browser.

By NaveenKumar T · Updated

Learn: JSON Examples: From Hello World to Real API Payloads

  • JSON or XML input, auto-detected
  • Nested objects become types
  • Nullability inferred

Runs entirely in your browser — nothing you paste or open here is uploaded, logged, or stored.How we handle data →

Example

Example: JSON order payload to Crystal

A small order document with a nested object, an array of two items, a decimal total and a null field — enough to show how each Crystal type, list and nullable is inferred. The same page accepts the XML form of this order too, so the sample below is an example rather than the only accepted format. The right-hand side is the exact output of this tool.

Input · JSON
{
  "id": "ord_9F2KX",
  "status": "processing",
  "paid": true,
  "customer": { "name": "Ada Lovelace", "email": "ada@example.com", "phone": null },
  "items": [
    { "sku": "KB-75", "qty": 1, "price": 149.99 },
    { "sku": "MS-12", "qty": 2, "price": 39.5 }
  ],
  "total": 228.99
}
Generated · Crystal
require "json"

class Root
  include JSON::Serializable

  property id : String

  property status : String

  property paid : Bool

  property customer : Customer

  property items : Array(Item)

  property total : Float64
end

class Customer
  include JSON::Serializable

  property name : String

  property email : String

  property phone : Nil
end

class Item
  include JSON::Serializable

  property sku : String

  property qty : Int32

  property price : Float64
end

Look for the "phone" field: sampled as null, it is typed as Nil. "items" became Array(Item), and "total" is Float64.

Learn more

From JSON sample to Crystal types

Hand-writing model classes from a JSON payload is transcription work: read a field, type a property, repeat eighty times, miss one. This page runs quicktype (the same engine behind the best-known generators) against your document, merging array elements to find the common shape and naming nested types from their keys.

Every field is declared with property, so the models are fully mutable; change the ones that should be read-only to getter once parsed. Root.from_json raises JSON::ParseException naming the failing property on drift — catch that specifically rather than a broad exception. The generated code needs no shard beyond the standard library's require "json".

How JSON values become Crystal types

Inference works from the values in your sample. Strings map to String, integers and decimals are told apart (228.99 becomes Float64, while 1 and 2 stay integral), true/false become the language's boolean, and an object such as "customer" becomes its own named type. The "items" array is typed as Array(Item) because every element shares the same keys — quicktype unifies the shapes of all array elements into one Item type.

Nulls are the one place inference needs your help: "phone": null carries no type information, so the field is emitted as Nil. If the real API sometimes sends a string there, include a sample where the field is populated (paste several documents merged into one array) and the generated type becomes the union of what it saw.

Pasting XML instead: how elements and attributes become Crystal types

The XML is parsed into a data model before inference (attributes included, text nodes named "text"), so the root element becomes a nested type: <order> is a field of type Order on the top-level Root rather than the top level itself. Child elements become fields, and repeated elements — the two <item> siblings — are collected into Array(Item) under an Items wrapper type that mirrors the <items> container.

Attributes and element text are typed differently, and this matters: element text is type-inferred, so <total>228.99</total> becomes Float64, while attribute values are kept as they were written — qty="1" and price="149.99" stay String in Crystal. Prefer element text for numeric data you want typed, or cast attribute values after decoding. One more trap: a single <item> would not be recognized as a list, so make sure repeated elements appear at least twice in the sample.

Annotations, nulls and nested arrays in the generated Crystal

Crystal classes include JSON::Serializable from the standard library, so from_json and to_json come for free with no shard to add. Renames use one annotation: a key such as customer-ref produces a JSON::Field annotation carrying key: "customer-ref" above a customer_ref property, while keys that are already valid identifiers get no annotation at all. Every field is declared with property, so the models are mutable. The same annotation accepts converter: and emit_null: if you need to reshape a single field without hand-writing the whole class.

A property whose only sampled value is null is typed Nil — the type with exactly one value — so it raises the moment a real string arrives. Add a document where the field carries a value and it becomes String?, shorthand for a String-or-Nil union that the compiler then forces you to handle. Properties missing from some of the merged samples become optional in the same way. An empty array is typed as an array of nullable JSON::Any, which means no element class was generated for it.

Nested objects become their own classes named from the key — Customer, Item — each including JSON::Serializable, so a single Root.from_json call walks the whole tree. Arrays of objects are typed Array(Item). Because Crystal checks these declarations at compile time and the parser enforces them at runtime, a payload that drifts raises JSON::ParseException naming the failing property instead of producing a half-built object. The usual two sample traps apply: one element hides optional fields, and an empty array generates no element class.

Help

Frequently asked questions

Everything you need to know about the JSON to Crystal.

01How do I generate Crystal classes from JSON?

Paste a representative document — JSON or XML, the format is detected automatically — and press Convert. A real API response works best. Nested objects become their own Crystal types, arrays become Array(Item), and the result downloads as Root.cr.

02What does the generated Crystal code include?

Crystal models use JSON::Serializable with typed properties — Ruby-like syntax with compile-time types, generated straight from your payload sample.

03How do I use the generated Crystal code in my project?

Save the file, require it, and call Root.from_json(string); to_json is available on every instance. The classes include JSON::Serializable from Crystal's standard library, so there is nothing to add to shard.yml.

04Why does the Crystal output look like typed Ruby?

Because Crystal is exactly that ambition: Ruby-flavored syntax, static types. JSON::Serializable in the standard library handles the mapping; the generated property types are where the value is.

Keep working

Related tools

Learn the format

Related guides

All guides →