JSON to Swift Struct Generator
Paste JSON, get Swift Codable structs — nested objects, arrays, CodingKeys, optionals — copy or download as .swift
Options
186 characters
2 structs generated · 458 characters
You’re building a SwiftUI app that consumes a REST API. The endpoint returns a JSON object with 25 fields, nested objects, and snake_case keys — but Swift conventions use camelCase. Writing the struct by hand means 25 let declarations, a CodingKeys enum to map every snake_case key, and a missed key quietly results in a silent decoding error.
What Is the Swift Codable Protocol?
Codable is a type alias for Encodable & Decodable. When a Swift struct conforms to Codable, the compiler automatically synthesizes encoding and decoding logic — no manual init(from:) required:
struct User: Codable {
let id: Int
let name: String
let email: String
}
let user = try JSONDecoder().decode(User.self, from: data)
Codable is the standard Swift pattern for working with JSON in iOS, macOS, watchOS, and server-side Swift (Vapor, Hummingbird). All Swift standard library types (String, Int, Double, Bool, Array, Optional) are already Codable.
Why Generate Structs from JSON?
REST API responses are defined by the server. A generator reads the actual JSON and produces correct Swift declarations automatically:
- Correct types: no more guessing if a field is
IntorDouble - Nested structs: each nested object becomes its own named struct
- CodingKeys: snake_case keys are mapped to camelCase Swift names automatically
- Speed: a 30-field JSON object becomes a ready-to-use struct in seconds
This tool runs entirely in your browser. Your JSON never leaves your device.
let vs var in Swift Structs
Swift structs use let for constant properties and var for mutable ones. For decoded API responses, let is almost always correct:
struct Product: Codable {
let id: Int // immutable — never changes after decoding
let name: String
let price: Double
}
If you need to mutate properties after decoding (e.g., for local state management), use var. However, keep in mind that with let properties in a struct, mutations require creating a new value:
var product = try decoder.decode(Product.self, from: data)
// Error: cannot assign to 'let' property
// Instead, define the struct with 'var' or use a separate mutable model
The generator uses let by default, which is idiomatic Swift for model types.
CodingKeys: Mapping snake_case to camelCase
REST APIs frequently return snake_case keys (first_name, is_active, created_at), but Swift conventions use camelCase (firstName, isActive, createdAt). The CodingKeys enum bridges this gap:
struct User: Codable {
let firstName: String
let isActive: Bool
enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case isActive = "is_active"
}
}
When CodingKeys is enabled, the generator emits the enum only when there are snake_case keys that differ from their camelCase form. Properties that are already camelCase are listed in CodingKeys without a raw value (Swift infers the string from the property name).
Alternatively, you can configure JSONDecoder globally to convert snake_case automatically:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// Now you don't need CodingKeys at all — but the generator
// still produces the enum for explicit, self-documenting models
Optional Handling
Swift’s Optional (?) is distinct from non-optional types at the compiler level. If you declare a property as String and the JSON is missing that key, decoding throws a DecodingError.keyNotFound error — which crashes if uncaught.
The optionals toggle makes all properties optional (String?, Int?, Bool?). This is defensive — it means missing keys produce nil instead of a crash, at the cost of having to unwrap everywhere:
// Non-optional (throws if key missing):
let name: String
// Optional (returns nil if key missing):
let name: String?
A practical approach: start with non-optional types, then add ? only to fields you know can be absent. The generator automatically makes properties optional when they are missing from some elements in an array of objects.
public vs internal Access
Swift’s default access level is internal — types are visible within the same module. When internal is selected, no access keyword is printed:
struct User: Codable { ... } // internal (default)
When public is selected, the generator adds the public keyword:
public struct User: Codable { ... } // accessible from other modules
Use public when building a Swift Package or framework that other modules import. For app code (a single module), internal is the right default.
How to Use This Tool
- Paste your JSON in the JSON Input textarea (or click Load sample)
- Set your root struct name (default:
Root) - Choose access level (
internalorpublic) - Toggle
Codable,optionals, andCodingKeysas needed - Click Copy to copy to clipboard, or Download .swift to save as a
.swiftfile - Paste into your Xcode project and use with
JSONDecoder
FAQ
Does this tool send my JSON to a server?
No. All processing happens entirely in your browser using JavaScript. Your JSON data never leaves your device.
How are nested objects handled?
Each nested JSON object becomes its own named Swift struct. The name is derived from the parent struct name plus the property key in PascalCase. For example, an address property inside Root generates a struct named RootAddress.
How are JSON arrays handled?
Arrays of plain objects are merged into a single struct. Properties missing from some elements become optional. Arrays of primitives map to [String], [Int], etc. Mixed arrays fall back to [Any].
What does Any? mean in the output?
Any? is generated for null JSON values where the actual type cannot be inferred. Note that Any is not Codable — you will need to replace Any? with a concrete Codable type or use a custom decoder for those fields.
Can I use this output with Alamofire or URLSession?
Yes. Both URLSession and Alamofire use JSONDecoder under the hood. The generated Codable structs decode directly:
URLSession.shared.dataTask(with: url) { data, _, _ in
guard let data else { return }
let result = try? JSONDecoder().decode(Root.self, from: data)
}
What if my JSON root is an array?
The tool generates a typealias for the root array (e.g., typealias Root = [RootItem]) and a separate struct for the element type. Decode it with JSONDecoder().decode([RootItem].self, from: data).
Does this work for SwiftUI @Observable or ObservableObject?
The generated structs are plain Codable value types. To use them with SwiftUI, decode the JSON into the struct and store it in an @Observable class or ObservableObject ViewModel. The struct itself does not need @Observable.