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
More on this site: all tools ·JSON formatter ·regex checker ·the arcade
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
.swiftfile.
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
Intfor integers — 64-bit on every platform Swift ships on, so big IDs are safe.Doublefrom the raw token — a field that ever showed a decimal point isDouble, even when another sample said5; the tool reads number tokens itself, keeping1and1.0distinct.let, notvar— 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.