JSON to Swift

Generate Swift Codable structs from a JSON sample — camelCase properties with a CodingKeys enum pinning the wire names wherever a spelling had to change, Optionals where keys come and go or turn null, and a small JSONValue enum appended for the slots the sample cannot settle, so the output still compiles. Free, no sign-up — runs locally in your browser.

Your work is auto-saved in this browser only, so a refresh won't lose it. Nothing is uploaded.

Why generate Swift structs from a sample?

Codable's synthesis is wonderful until a key goes missing: then a decode that worked on every sample you tried throws in production, because the property you declared non-optional was absent from the response you never saw. Swift model code is a set of claims — this key always exists, it is always a string, its name is camelCase — and the sample is the only evidence available for those claims before the app ships. This converter reads the sample the way a careful reviewer would: objects become Codable structs, arrays become [T], absence and null become Optionals, renames produce a complete CodingKeys enum that pins every wire name, and the slots no sample could settle become a small JSONValue enum that is appended, explained, and ready to compile — not an Any that Swift would reject.

How to use this tool

  1. Paste the JSON. A real API response is ideal; include several array elements if you have them, because absence across elements is how Optional properties are discovered.
  2. Name the root struct. Root is fine for a quick look; for code you will keep, use the name it will wear in your project.
  3. Press Generate Swift. The root struct comes first, the structs it references after it, and the JSONValue helper last if it is needed.
  4. Read the notes if any appear. They list every JSONValue slot, every backticked keyword property and every name collision — nothing was decided silently.
  5. Copy or download the result, then refine it: adjust CodingKeys where your API's naming has rules a sample cannot show, swap in Date or URL where strings are really those, and let the compiler take it from there.

The rules it follows

Numbers. Whole numbers become Int; any fraction widens the slot to Double — a JSON 1.0 is the number 1 to every parser, so a field your API always sends as 2.0 reads as an integer sample unless a real fraction appears. Names. Structs are PascalCase after the key that holds them; properties are camelCase. When a property's spelling differs from its key, the struct gains a CodingKeys enum listing every property — renamed ones with their raw value, others bare — because a partial enum is a trap. Absence and null. Missing from some elements or sometimes null → Optional. Null everywhere or genuinely mixed types → JSONValue, with the helper enum appended and the slot noted. Merging. Identical shapes — same keys, same types — share one struct instead of being emitted twice.

Worked example

Given this sample (the second user has no nickname, and the keys are already camelCase):

{
  "teamName": "Platform",
  "users": [
    { "id": 1, "firstName": "Ada", "nickname": "ada" },
    { "id": 2, "firstName": "Grace" }
  ]
}

the converter emits — no CodingKeys are needed, because no name had to change:

struct Root: Codable {
    let teamName: String
    let users: [User]
}

struct User: Codable {
    let id: Int
    let firstName: String
    let nickname: String?
}

The String? is the second user talking: a non-optional nickname would make JSONDecoder throw on exactly that response. Had the sample spelled that key first_name, User would also carry a CodingKeys enum listing all three properties, with case firstName = "first_name" pinning the wire name.

Frequently asked questions

Why do some structs have a CodingKeys enum and others don't?

Swift's synthesized Codable conformance matches property names to JSON keys exactly. When every key in a struct is already spelled the way the camelCase property is — most keys in most APIs — the synthesis is correct as-is and a CodingKeys enum would be pure noise. The moment one property's name differs from its key (a snake_case key, a keyword written in backticks), the struct needs the enum, and it then lists EVERY property, not just the renamed one: a partial CodingKeys enum discards the compiler's synthesis for the unlisted properties too, which fails in ways that eat an afternoon. So the enum appears exactly when it is needed, and complete when it appears.

When does a property become Optional (String? instead of String)?

When the sample shows the value can fail to be there: the key is missing from some elements of an array, or it is present but sometimes null. JSONDecoder is unforgiving here in a way that makes this matter — a non-optional property whose key is absent throws keyNotFound and fails the whole decode, not just that field. Optional turns 'sometimes absent' into a value you can handle, which is the truthful model of what the sample shows.

What is the JSONValue enum at the bottom of some outputs?

The fallback for slots the sample could not settle: a key that is null everywhere (no evidence what it would hold), or one that genuinely mixes types across elements. Swift has no built-in 'any JSON value' type, so rather than emit code that cannot compile, the generator appends a small recursive JSONValue enum — string, int, double, bool, array, object, null — with a working Codable conformance, and types those slots with it. The notes list every slot that uses it and why. If your API stabilises, regenerate with a better sample and the enum disappears.

Why Int for whole numbers and Double for fractions?

Because Codable decodes what the type declares, and the sample distinguishes the two: a slot that only ever shows whole numbers becomes Int, a single fractional sighting makes it Double — Int cannot hold the 2.5 your API demonstrably sends. The mirror trap also applies: JSON 1.0 is the number 1 to every parser, so a field your API always sends as 2.0 samples as an integer here. If a value must survive as a decimal exactly (money), that is a modelling decision for after generation — Decimal is not inferred from spelling.

One property is written in backticks (`class`). Why?

Your JSON has a key that is a Swift keyword. Swift permits keywords as member names in backticks — let `class`: String is legal — and the property's CodingKeys entry pins the wire name without them, so decoding looks for "class" as it should. The notes flag each backticked property. If your style guide forbids them, rename the property and keep its CodingKeys entry, which is doing the real work.

Should the properties be let or var?

The generator emits let, because a decoded model value is a fact about what the API sent, and immutability is the safer default to review from. If your design mutates models in place, changing let to var on the structs you keep is a mechanical pass — Codable does not care either way. What it does care about (names, optionality, the CodingKeys mapping) is the part this tool settles.

Related tools