JBird
A blazing fast, type-safe library for working with JSON in Swift
Why JBird?
Between the Standard Library and Foundation, Swift developers have two standard methods to read JSON, neither of which are ideal:
JSONSerializationreturns values of typeAny. You must cast and unwrap each value before it can be used.Codableis type-safe. But your Swift types must have the same structure as the JSON document. It is difficult to read one field from a document that has no matching Swift type.
JBird a complete, standardized way to work with JSON documents in Swift that solves both of these issues, and then some. It stores a JSON document as a Swift value of type JSON. You can read, move through, and change this value directly. The compiler checks the types at each step. A parser written in C reads the document into this value.
JBird can also convert a JSON value to and from your own Swift types. This includes an encoder and a decoder that you can use in place of JSONEncoder and JSONDecoder.
// Foundation: cast and unwrap at each level
if let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let user = root["user"] as? [String: Any],
let name = user["name"] as? String {
// ...finally usable
}
// JBird: read the value in one expression
let json = try JSON(data)
let name: String = try json["user"]["name"]
For more information, see the documentation.
Features
JBird is organized around five capabilities, all built on the same JSON value type — so they share a consistent, type-safe API and compose freely.
A type-safe model for creating and manipulating JSON
JSON is an enum with one case per JSON valid type (null, bool, number, string, array, object).
public enum JSON {
case null
case bool(Bool)
case number(Number)
case string(String)
case array([JSON])
case object([String: JSON])
}
It conforms to the standard ExpressibleBy*Literal protocols, so you build values using ordinary Swift literals:
var user: JSON = [
"name": "Alice",
"age": 30,
"active": true,
"roles": ["admin", "editor"],
]
Read values through throwing, typed accessors and subscripts. Subscripts chain across nested objects and arrays, and can convert to a concrete type inline:
let name = try user["name"].convert(to: String.self) // String
let firstRole: String = try user["roles"][0] // String, via type inference
let age = try user["age", as: Int.self] // Int
if user.containsValue(forKey: "email") { /* ... */ }
Mutate in place — set keys, append to arrays, merge, and remove — without rebuilding intermediate containers:
try user.setValue(31, forKey: "age")
try user["roles"].append("reviewer")
try user.removeValue(forKey: "active")
try user.merge(["verified": true], uniquingKeysWith: { _, new in new })
A blazing fast JSON serializer and deserializer
Parsing and serialization are backed by a hand-written C. It works directly with the JSON model, with no intermediate Any representation to slow things down.
// Deserialize from Data or String
let json = try JSON(data)
let fromString = try JSON(jsonString: #"{"ok":true}"#)
// Serialize to Data or String
let data = try json.serialize()
let string = try json.stringify()
Both directions can be customized for control over things like pretty-printing, key sorting, and duplicate-key handling. Cancellable async variants are available for large payloads.
Conversion between typed JSON and Swift types
JBird defines a small protocol family for bridging typed JSON and other Swift types:
JSONConvertible— a type can produce aJSONvalue (var jsonValue: JSON)JSONInitializable— a type can be built from aJSONvalue (init(json:) throws)JSONRepresentable— both of the above
Many standard library types already implement conformance for you out of the box.
let json = JSON(["a": 1, "b": 2]) // from a Swift dictionary
let dict = try json.convert(into: [String: Int].self)
For your own types, the @JSONRepresentable macro can leverage the compiler to automatically implement conformance in many / most cases
@JSONRepresentable
struct Article {
@JSONKey("article_id") let id: String
@JSONKey(.snakeCase) let publishedAt: Date // -> "published_at"
@OmitIfNil let summary: String?
}
let article = try Article(json: json)
let roundTrip = JSON(article)
A result builder for declarative JSON
The JSON { ... } result builder constructs values declaratively, with the => operator for object keys, nesting via trailing closures, and full support for if/else/for control flow:
let payload = JSON {
"id" => 123
"profile" => {
"name" => "Alice"
if isAdmin {
"role" => "admin"
}
}
"tags" => {
for tag in tags {
tag
}
}
}
A drop-in replacement for JSONEncoder / JSONDecoder
JSON.Encoder and JSON.Decoder mirror Foundation’s Codable API surface, so existing Codable types work unchanged — while encoding and decoding run through JBird’s fast core, no migration required.
struct Person: Codable {
let name: String
let age: Int
}
let encoder = JSON.Encoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
encoder.keyEncodingStrategy = .convertToSnakeCase
let data = try encoder.encode(Person(name: "Bob", age: 25))
let decoder = JSON.Decoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let person = try decoder.decode(Person.self, from: data)
The familiar configuration strategies are all present, along with support for EncodableWithConfiguration / DecodableWithConfiguration.
The declarative builder, conformance macros, and
Codablesupport are exposed as package traits —DeclarativeAPI,ConformanceMacros, andCodableSupport— all enabled by default and individually opt-out.
JBird is rigorously validated against RFC 8259 by a comprehensive test suite and a software fuzzer.
Installation
JBird is primarily distributed through the Swift Package Manager.
To add JBird as a dependency to an existing Swift package, add the following line of code to the dependencies parameter of your Package.swift file:
dependencies: [
.package(url: "https://github.com/vsanthanam/JBird.git", from: "2.3.1")
]
Then, add the JBird dependency to your target or targets of choice:
.target(
name: "YourTarget",
dependencies: [
.product(name: "JBird", package: "JBird")
]
)
Xcode
JBird supports the full range of Apple platforms when working with Xcode, whether you build from source or use an XCFramework:
| Platform | Minimum Version | Status |
|---|---|---|
| macOS | 13.0+ | ✅ Supported |
| Mac Catalyst | 16.0+ | ✅ Supported |
| iOS | 16.0+ | ✅ Supported |
| watchOS | 9.0+ | ✅ Supported |
| tvOS | 16.0+ | ✅ Supported |
| visionOS | 1.0+ | ✅ Supported |
Swift Package Manager
JBird has been tested to work with the following platforms and Swift toolchains:
| Platform | Swift Versions | Status |
|---|---|---|
| macOS | 6.2, 6.3, and 6.4 | ✅ Supported & Tested |
| Linux (Ubuntu) | 6.2, 6.3, and 6.4 | ✅ Supported & Tested |
| Windows | 6.2, 6.3, and 6.4 | ✅ Supported & Tested |
| WebAssembly | 6.2, 6.3, and 6.4 | ⚠️ Supported (No Tests) |
| Android | 6.2, 6.3, and 6.4 | ⚠️ Supported (No Tests) |
All supported platforms undergo continuous integration testing to ensure compatibility across different environments. Other platforms such as FreeBSD may also work, but are not validated in the built-in GitHub Actions powered CI environment.
For additional installation instructions, see the documentation.
Performance
JBird is designed with performance and memory efficiency in mind, with benchmarks showing it to be one of the fastest JSON parsers available for Swift. The core parsing engine is written in C, and is heavily optimized, making it significantly faster than pure Swift alternatives.
On realistic JSON documents ranging from 64KB to 5MB, in both minified and pretty-printed formats, JBird compares favorably to other popular Swift JSON parsing libraries:
- Speed: JBird parses about 2x faster than Foundation’s
JSONSerialization, about 2x faster than Freddy, and 7-8x faster than SwiftyJSON - CPU Work: JBird executes roughly half the CPU instructions of Foundation and Freddy, and about one eighth the instructions of SwiftyJSON, for equivalent payloads
- Memory Efficiency: JBird’s peak memory use is 85-90% lower than Foundation’s and 60-70% lower than SwiftyJSON’s, and on par with Freddy’s
- Allocations: JBird performs about 30% fewer heap allocations than Foundation and about 50% fewer than SwiftyJSON
- Consistent Performance: JBird’s advantage holds steady across file sizes and formats, and grows on string-heavy inputs, where it is 8-11x faster than every library measured
You can explore the full comparisons with Foundation, Freddy, and SwiftyJSON, including percentile breakdowns for wall clock time, throughput, instructions, memory, and allocations, in the /Benchmarks directory.
Usage & Documentation
JBird’s documentation is built with DocC and included wich each release as a DocC archive. The latest version is hosted on GitHub Pages and is available here.
Additional information is available on the Swift Package Index
Explore the documentation for more details.
License
JBird is available under the MIT license. See the LICENSE file for more information.