Skip to content

Tools

JSON to Swift

Paste JSON, get Codable structs ready forJSONDecoder — CodingKeys where keys need renaming, optionals only where your sample proves them. Runs entirely in your browser.

Generated code

Beta — the generated code is unit- and compile-tested, but inference from one sample can't be perfect; on rare occasions the output may need a tweak. Spot something wrong?Tell me.

What is this tool?

A free JSON-to-Swift converter. Paste a JSON document and it generates Codable structs for the whole tree — immutable let properties, camelCase names with a CodingKeys enum wherever the original key needed renaming, and nested structs named from their keys. The output leans on Codable's synthesized conformance: no hand-rolled init(from:) boilerplate to maintain, just try JSONDecoder().decode(Response.self, from: data).

Your JSON never leaves the browser. Everything is client-side; the page works offline once loaded.

How to use it

  • Paste JSON on the left — Swift appears on the right as you type.
  • Name the root struct; nested structs are named from their keys, singularized inside arrays (users: […] → User).
  • Check the warnings panel: every under-specified spot in your sample is named by JSON path.
  • Copy or Download the .swift file.

CodingKeys, only when they earn their keep

When every JSON key is already a clean Swift name, Codable synthesizes the mapping and the struct stays three lines. The enum appears only in structs where at least one key needed work — and then it lists every field, because a partialCodingKeys silently drops the rest (a classic Codable trap):

enum CodingKeys: String, CodingKey {
    case id
    case createdAt = "created-at"
}

Reserved words are handled the same way — a key namedclass becomes class_ with its mapping preserved — and diacritics or leading digits are cleaned up (1st-place → the1stPlace).

Optionals from evidence, not fear

Converters that make every property optional produce unwrapping fatigue; ones that make everything non-optional crash on the first null. This tool types from your sample: a field that was present and non-null everywhere is non-optional; a field that was null or missing anywherebecomes T?. That maps cleanly onto Codable, where an optional property decodes via decodeIfPresent — a missing key and an explicit null both becomenil, and encoding a nil omits the key. If you don't trust your sample, flip on All fields optional.

Why dates stay String

Swift can decode ISO timestamps into Date — but only if you configure the decoder (decoder.dateDecodingStrategy = .iso8601), and that strategy rejects fractional seconds and date-only strings like2026-07-01. Struct code can't guarantee decoder configuration, so generating Date would produce models that compile and then throw at runtime depending on a setting elsewhere. Detected date fields are typedString with an /// ISO 8601 doc comment; parse where you consume them with ISO8601DateFormatter(enable .withFractionalSeconds if needed).

JSONValue — because Codable has no Any

When the sample can't pin a field down (always null, an empty array, a string in one element and a number in another), most converters emit Any — which doesn't conform toCodable and doesn't compile. This tool emits a compact JSONValue enum once (null, bool, number, string, array, object with full Codable conformance) and types those fields with it: decodable, pattern-matchable, honest. Each such field also gets a warning naming its JSON path — the better fix is usually a richer sample.

Type choices worth knowing

  • Int for integers — 64-bit on every platform Swift ships on, so big IDs are safe.
  • Double from the raw token — a field that ever showed a decimal point is Double, even when another sample said 5; the tool reads number tokens itself, keeping 1 and 1.0 distinct.
  • let, not var — decoded models are values; mutate by making a copy, per Swift's own grain.

FAQ

Is it free? Yes — free, no sign-up, no limits.

Is my JSON uploaded anywhere? No — fully client-side, works offline after load; only your last input is kept, in your own browser's local storage.

Why did decoding throw keyNotFound?A non-optional property met a payload that omitted its key — your generation sample said the key was always there, this response disagreed. Either regenerate with a richer sample or make that property optional.

SwiftData / Core Data models? Out of scope — those are persistence schemas, not transport models. Decode with these structs, then map into your store.

Can it read a JSON Schema? Not yet — v1 infers from samples; schema input is planned.

Built from scratch for this site in vanilla TypeScript — a pure, unit-tested inference engine with golden-tested emitters and zero runtime dependencies.