iOS developer & learning

JSON to Swift Codable converter

Paste a JSON response and get Swift Codable types: nested structs, optionals merged across array items, CodingKeys or convertFromSnakeCase, Date and URL detection, and a matching decoder.

Converted in this tab; this tool's code doesn't upload your JSON.

Paste JSON to start.

    Swift types

    Decoding it

    Free to use, no account. More developer tools

    How types are inferred

    • Whole numbers become Int; anything with a decimal point or exponent becomes Double, even 1.0. The parser keeps the number as written, so 1.0 is not mistaken for an integer, and integers too large for Int become Double.
    • Arrays of objects are merged: every element is read, keys that are missing from some elements or are null in any of them become optionals, and Int mixed with Double becomes Double.
    • Objects with exactly the same shape share one type, so an author and an editor with the same keys produce one struct.
    • Array element types are named in the singular: posts gives [Post], categories gives [Category].
    • Strings that are ISO-8601 date-times become Date, and http or https strings become URL. Turn either off if your API sends odd values in those fields.
    • A field that is only ever null, an empty array, or a mix of types gets JSONValue, a small enum included in the output. Replace it once you know the real type.

    CodingKeys or convertFromSnakeCase

    With CodingKeys every Swift name is camelCase and the enum maps it to the JSON key, for example case createdAt = "created_at". It is explicit, survives renames and works for keys like user-name. With convertFromSnakeCase the decoder converts keys itself and the structs stay short. Watch its rule: it lowercases the first word and capitalises the rest, so user_ID becomes userId, not userID. When a key can't be converted to a valid Swift name, the generator still writes a CodingKeys entry using the converted name, which is what the decoder compares against.

    Dates, money and Sendable

    • The decoder snippet matches the output. Plain ISO dates use .iso8601. If any sample date has fractional seconds, such as 2026-10-25T06:30:00.123Z, .iso8601 alone fails, so you get a .custom strategy with .withFractionalSeconds.
    • Amounts of money arrive as JSON numbers but should not be added up as Double. Change those properties to Decimal; JSONDecoder decodes it from a number.
    • Sendable is on by default because value types with let properties qualify. A final class with var properties doesn't, and the generator says so rather than adding @unchecked.

    Big files

    Responses up to a few megabytes convert as you type. Larger input moves to a Web Worker so the page stays responsive, and this tool's code still doesn't send the JSON anywhere. The sample shapes the types: if a key is missing from every element you pasted, it can't appear in the output, so paste a response that includes the optional fields.

    Questions

    Should I use CodingKeys or convertFromSnakeCase?

    CodingKeys if you want every mapping visible in code or the keys mix styles; convertFromSnakeCase if the API is consistently snake_case and you want short structs. Don't use both for the same key: with the strategy on, CodingKeys values must be the converted names.

    How are optionals decided?

    A property is optional if any sample value is null or if the key is missing from at least one object in an array. Paste a response with as many cases as you have, because a key that is always present in the sample is generated as non-optional.

    How do I decode ISO-8601 dates?

    Set decoder.dateDecodingStrategy = .iso8601 for dates like 2026-10-25T06:30:00Z. For dates with fractional seconds, use a custom strategy with ISO8601DateFormatter and .withFractionalSeconds; the generator writes it for you when the sample needs it.

    What about mixed arrays and mixed number types?

    Int and Double in the same field become Double. Other mixes, like numbers and strings, become JSONValue, an enum that decodes any JSON value. Replace it with a concrete type or a custom init(from:) once you know the rules.

    Is my JSON uploaded?

    No. The JSON is converted in this tab, and this tool's code doesn't upload it. Large input is handled by a Web Worker in the same tab.

    From the same developer

    • Catalog - UI screenshot 1
    • Catalog - UI screenshot 2
    • Catalog - UI screenshot 3