DevToolsmith

JSON to Swift Codable Converter

Paste JSON to generate Swift structs that conform to Codable. Keys become camelCase properties with CodingKeys, nullable values become optionals, and dates, URLs and UUIDs can get their own types.

Runs 100% in your browser — nothing is uploaded

JSON
Tip: drop a file here361 chars · 361 bytes · 14 lines
Swift Codable structs
3,071 chars · 3,071 bytes · 84 lines

Tip: paste an array of several objects — keys missing from some of them become optional (T?).

Example

JSON input
[
  {
    "id": 42,
    "full_name": "Ada Lovelace",
    "avatar_url": "https://example.com/ada.png",
    "joined_at": "2026-03-14T09:26:53Z",
    "roles": [
      "admin"
    ]
  },
  {
    "id": 43,
    "full_name": "Grace Hopper",
    "avatar_url": null,
    "joined_at": "2026-04-01T12:00:00Z",
    "roles": [],
    "team": {
      "id": 7,
      "name": "Compilers"
    }
  }
]
Generated Swift (root name: User, with Date types)
import Foundation

// The JSON root is an array: decode [UserItem].self
// Dates are ISO 8601: set decoder.dateDecodingStrategy = .iso8601Flexible (below; the built-in .iso8601 rejects fractional seconds)

struct UserItem: Codable {
    let id: Int
    let fullName: String
    let avatarUrl: URL?
    let joinedAt: Date
    let roles: [String]
    let team: Team?

    enum CodingKeys: String, CodingKey {
        case id
        case fullName = "full_name"
        case avatarUrl = "avatar_url"
        case joinedAt = "joined_at"
        case roles
        case team
    }
}

struct Team: Codable {
    let id: Int
    let name: String
}

extension JSONDecoder.DateDecodingStrategy {
    /// ISO 8601 date-times with or without seconds and fractional seconds; .iso8601 only reads whole seconds.
    static var iso8601Flexible: Self {
        .custom { decoder in
            let text = try decoder.singleValueContainer().decode(String.self)
            // "2026-01-01T09:00Z" has no seconds, which ISO8601DateFormatter requires.
            let full = text.replacingOccurrences(of: #"T(\d{2}:\d{2})(?=Z|[+-])"#, with: "T$1:00", options: .regularExpression)
            let f = ISO8601DateFormatter()
            for options: ISO8601DateFormatter.Options in [[.withInternetDateTime, .withFractionalSeconds], [.withInternetDateTime]] {
                f.formatOptions = options
                if let date = f.date(from: full) { return date }
            }
            throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Not an ISO 8601 date-time: \(text)"))
        }
    }
}
  • full_name became fullName, mapped back in CodingKeys.
  • avatar_url is null for one user, so it is optional. It looks like a URL, so it is URL?.
  • team only appears for one user, so it is Team? and may be missing from the JSON.
  • joined_at is an ISO 8601 timestamp, so it is a Date.

Decoding with JSONDecoder

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

let user = try decoder.decode(User.self, from: data)
print(user.fullName)

// An array at the root decodes the same way
let users = try decoder.decode([User].self, from: data)

let encoded = try JSONEncoder().encode(user)

Type mapping

JSONSwift
stringString (or Date, URL, UUID)
integerInt (64-bit), UInt64 or Decimal for larger values
decimal numberDouble
true / falseBool
objectstruct … : Codable
array[T]
sometimes missing or nullT?
mixed typesJSONValue

Building for Android too? Generate Kotlin data classes or Dart classes for Flutter from the same JSON.

Frequently asked questions

How do I convert JSON to a Swift struct?

Paste a JSON sample into the tool above. It creates a Codable struct for every object, converts snake_case keys to camelCase properties with a CodingKeys enum for the original names, and makes values that are null or missing in some samples optional.

Do I need CodingKeys, or can I use convertFromSnakeCase?

Either works for plain snake_case keys. Setting decoder.keyDecodingStrategy = .convertFromSnakeCase removes the need for CodingKeys, but it also changes keys you didn’t expect (user_id becomes userId, not userID) and applies to every type. CodingKeys are explicit and keep working whatever decoder the struct is used with.

Why does decoding fail with keyNotFound?

A non-optional property is missing from the JSON. Paste several samples as an array so the converter can see which keys are sometimes absent; it makes those properties optional, and Codable then accepts a missing key as nil.

How are dates decoded?

With Date, URL and UUID types ticked, ISO 8601 strings become Date. JSONDecoder doesn’t read ISO 8601 by default, so set decoder.dateDecodingStrategy = .iso8601 (for fractional seconds, use a custom ISO8601DateFormatter with .withFractionalSeconds). Leave the box unticked to keep dates as String.

What is the JSONValue enum for?

Swift has no Codable “any” type. When a field holds different types in different samples, for example a number in one and a string in another, the converter adds a small JSONValue enum that can decode and encode any JSON value.