Skip to content

Tools

JSON to Swift

Paste JSON, get Codable structs ready forJSONDecoderCodingKeys 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-placethe1stPlace).

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.