JSON to Swift Struct Generator

Generate Swift Codable struct definitions from JSON with automatic type inference, CodingKeys enum, and nested struct support.

What is JSON to Swift Struct Generator?

Swift's Codable protocol is the standard for JSON parsing in iOS, macOS, and server-side Swift (Vapor). A type conforming to Codable can be decoded from JSON with a single line — JSONDecoder().decode(MyType.self, from: data) — but first you need the struct definition with the right property names and types. Writing it by hand is tedious: Swift uses camelCase by convention but REST APIs often return snake_case, requiring a CodingKeys enum to map between them. Null-safe optional types (String? vs String) must be correctly chosen for every field, or the decoder will throw a typeMismatch error at runtime. This generator handles all of that: it infers Swift types from JSON values, converts keys to camelCase, generates CodingKeys enums only when needed (i.e. when the JSON key and Swift property name differ), marks null fields as optional, and optionally maps ISO-8601 strings to Swift's Date type.

How to Use

  1. Set the root struct name to match what the response represents (e.g. "Tweet", "ProductDetail") — it becomes the top-level Swift type
  2. Enable "Detect dates" if your JSON contains ISO-8601 date strings — they will be typed as Date instead of String. Use this with JSONDecoder().dateDecodingStrategy = .iso8601 in your decoding code
  3. Paste your JSON and click "Generate Swift Structs" — the output is ready to paste into an .swift file in your Xcode project
  4. Add import Foundation at the top of the file if the output uses Date
  5. Use the struct directly with JSONDecoder: let result = try JSONDecoder().decode(YourType.self, from: jsonData)

Why Use This Tool?

Generates Codable-conforming structs — one derive line and the Swift compiler generates all encode/decode logic
CodingKeys enum is only generated when needed — when the JSON key and Swift property name are identical, CodingKeys is omitted to keep the output clean
Correctly marks null fields as optional (String?) — optional types prevent runtime typeMismatch crashes when a field is absent
Handles snake_case → camelCase conversion with CodingKeys rather than a global decoder strategy, giving you per-field control
Nested structs are ordered children-first, matching Swift's compilation requirement
Compatible with URLSession, Alamofire, and any networking library that returns Data

Tips & Best Practices

  • When all your JSON keys use snake_case, you can skip CodingKeys entirely by setting decoder.keyDecodingStrategy = .convertFromSnakeCase on your JSONDecoder instance — this is cleaner than per-field CodingKeys for large structs
  • For optional nested objects, Swift uses T? (e.g. Address?) — when the field is null in JSON, the property is nil rather than an empty struct, which lets you safely use optional chaining (user.address?.city)
  • Date decoding requires matching the date format in the JSON — ISO-8601 strings ("2024-01-01T00:00:00Z") work with .iso8601 strategy; Unix timestamps (integers) require a .secondsSince1970 strategy
  • If a field is sometimes a String and sometimes an Int (a common backend anti-pattern), use AnyCodable from the AnyCodable package or decode as serde_json::Value — the generator cannot handle union types
  • Swift structs are value types (copied on assignment) — for large deeply nested responses used in multiple places, consider using classes (reference types) to avoid copying overhead

Frequently Asked Questions

What is the complete JSON type → Swift type mapping?

JSON string → String (or Date if ISO-8601 detected). JSON integer → Int. JSON float → Double. JSON boolean → Bool. JSON null → T? where T is inferred from the structure. JSON array → [T] with T inferred from the first element. JSON object → a named struct. Heterogeneous arrays → [Any] (requires custom Codable implementation). There is no direct Swift equivalent of JSON's dynamic typing for specific fields.

What is the CodingKeys enum and when is it generated?

CodingKeys is a nested enum inside the struct that maps Swift property names to JSON string keys. It is needed when the Swift name and JSON key differ — for example, the JSON key "user_name" must be mapped to the Swift property "userName" via case userName = "user_name". This generator only emits CodingKeys when at least one property name differs from its JSON key, keeping the output minimal when all names match.

What is Codable and how does it work?

Codable is a Swift type alias for the combination of Encodable (struct → JSON) and Decodable (JSON → struct) protocols. When you write struct Foo: Codable, the Swift compiler synthesizes encode(to:) and init(from:) implementations automatically — as long as all property types are themselves Codable. This means String, Int, Bool, Double, Date, Array, Optional, and other Codable types work out of the box; custom types need to conform to Codable too.

When should I use a class instead of a struct for JSON models?

Use a class when: (1) the model is large and frequently passed between view controllers or layers, where value-type copying is a performance concern; (2) you need reference semantics (two variables pointing to the same object); (3) you are working with SwiftUI's ObservableObject pattern. Use a struct (the default) for simple API response models — value semantics and automatic copy-on-write make structs safer and more predictable for data transfer objects.

When should I NOT use the generator?

Skip it for polymorphic JSON — responses where a "type" field determines the shape of the rest of the object. These require a custom init(from decoder: Decoder) implementation with nested container decoding. Also skip it for responses with arbitrary dynamic keys (use [String: SomeType] dictionaries instead) or for binary formats like Protobuf where Codable is not the right tool.

Is my data sent to a server?

No. All struct generation runs entirely in your browser. Your JSON data never leaves your device.

Real-world Examples

Decoding an App Store Connect API response

Apple's App Store Connect API returns snake_case keys with nested data objects. The generator converts the keys to camelCase and adds CodingKeys for the mappings. The "attributes" nested object becomes a separate struct.

Input
{
  "type": "apps",
  "id": "1234567890",
  "attributes": {
    "name": "My Awesome App",
    "bundle_id": "com.example.myapp",
    "primary_locale": "en-US",
    "is_or_ever_was_made_for_kids": false,
    "subscription_status_url": null
  },
  "links": {
    "self": "https://api.appstoreconnect.apple.com/v1/apps/1234567890"
  }
}
Output
import Foundation

struct Links: Codable {
    let selfLink: String

    enum CodingKeys: String, CodingKey {
        case selfLink = "self"
    }
}

struct Attributes: Codable {
    let name: String
    let bundleId: String
    let primaryLocale: String
    let isOrEverWasMadeForKids: Bool
    let subscriptionStatusUrl: String?

    enum CodingKeys: String, CodingKey {
        case name
        case bundleId = "bundle_id"
        case primaryLocale = "primary_locale"
        case isOrEverWasMadeForKids = "is_or_ever_was_made_for_kids"
        case subscriptionStatusUrl = "subscription_status_url"
    }
}

struct AppResponse: Codable {
    let type: String
    let id: String
    let attributes: Attributes
    let links: Links
}

Parsing a date-heavy event response with optional location

Calendar or event APIs commonly return ISO-8601 timestamps and optional nested objects for fields like venue. Enabling "Detect dates" maps the start and end fields to Swift Date, and the nullable venue becomes Venue?.

Input
{
  "eventId": "evt_5521",
  "title": "WWDC 2025 Keynote",
  "startDate": "2025-06-09T17:00:00Z",
  "endDate": "2025-06-09T19:00:00Z",
  "isOnline": true,
  "attendeeCount": 5000,
  "venue": null
}
Output
import Foundation

struct Venue: Codable {}

struct Event: Codable {
    let eventId: String
    let title: String
    let startDate: Date
    let endDate: Date
    let isOnline: Bool
    let attendeeCount: Int
    let venue: Venue?

    enum CodingKeys: String, CodingKey {
        case eventId, title, startDate, endDate, isOnline, attendeeCount, venue
    }
}

// Usage:
// let decoder = JSONDecoder()
// decoder.dateDecodingStrategy = .iso8601
// let event = try decoder.decode(Event.self, from: jsonData)

Related Tools