https://github.com/tayloraswift/swift-bson
parse, decode, and encode BSON in pure Swift
https://github.com/tayloraswift/swift-bson
bson mongdb serialization
Last synced: 12 months ago
JSON representation
parse, decode, and encode BSON in pure Swift
- Host: GitHub
- URL: https://github.com/tayloraswift/swift-bson
- Owner: tayloraswift
- License: apache-2.0
- Created: 2024-11-18T23:48:17.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2025-04-13T21:50:25.000Z (about 1 year ago)
- Last Synced: 2025-06-07T23:54:01.376Z (about 1 year ago)
- Topics: bson, mongdb, serialization
- Language: Swift
- Homepage: https://swiftinit.org/docs/swift-bson/bson/examples
- Size: 208 KB
- Stars: 11
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
***`bson`***
[](https://github.com/tayloraswift/swift-bson/actions/workflows/Tests.yml)
[](https://github.com/tayloraswift/swift-bson/actions/workflows/Documentation.yml)
The ***swift-bson*** library is a portable, Foundation-free library for working with [BSON](https://bsonspec.org/).
[documentation](https://swiftinit.org/docs/swift-bson) Β·
[license](LICENSE)
## Requirements
The swift-bson library requires Swift 6.0 or later.
| Platform | Status |
| -------- | ------ |
| π§ Linux | [](https://github.com/tayloraswift/swift-bson/actions/workflows/Tests.yml) |
| π Darwin | [](https://github.com/tayloraswift/swift-bson/actions/workflows/Tests.yml) |
| π Darwin (iOS) | [](https://github.com/tayloraswift/swift-bson/actions/workflows/iOS.yml) |
| π Darwin (tvOS) | [](https://github.com/tayloraswift/swift-bson/actions/workflows/tvOS.yml) |
| π Darwin (visionOS) | [](https://github.com/tayloraswift/swift-bson/actions/workflows/visionOS.yml) |
| π Darwin (watchOS) | [](https://github.com/tayloraswift/swift-bson/actions/workflows/watchOS.yml) |
[Check deployment minimums](https://swiftinit.org/docs/swift-bson#ss:platform-requirements)
## What is BSON?
[BSON](https://bsonspec.org/) is a general-purpose binary serialization format that is a superset of [JSON](https://www.json.org/). Parsing BSON requires much less memory than parsing JSON, and the format is traversable, which makes it possible to extract individual fields nested deep within a BSON document without actually parsing the entire file.
BSON was originally developed by [MongoDB](https://www.mongodb.com/), for which it serves as its native data format. However, the file format itself is not tied to MongoDB, and can be used in any system that requires a high-performance, low-memory serialization format.
## Why do I need this library?
If you are using [MongoKitten](https://github.com/orlandos-nl/MongoKitten), your MongoDB driver already includes a BSON parser based on the standard libraryβs [`Codable`](https://swiftinit.org/docs/swift/swift/codable) system, which has the advantage of generating much of the deserialization code for you automatically. However, `Codable` has well-known performance limitations, and is not suitable for high-throughput use cases.
Another reason to use this library is that it is portable and has few dependencies. BSON parsers provided by MongoDB drivers have dependencies on networking primitives such as [`ByteBuffer`](https://swiftinit.org/docs/swift-nio/niocore/bytebuffer), which requires you to link the [SwiftNIO library](https://github.com/apple/swift-nio). For applications that simply use BSON as a storage format, this may not be desirable.
## Is it faster than Codable?
The decoder is approximately 3 to 6 times faster than the default MongoKitten decoder. The encoder has similar throughput to `Codable`.
([Benchmark source code](/Benchmarks/Benchmarks/VsMongoKittenDefault))
Performance comparison
```
Host 'vscode' with 12 'x86_64' processors with 30 GB memory, running:
#202408030740 SMP PREEMPT_DYNAMIC Sat Aug 3 07:53:03 UTC 2024
====================
VsMongoKittenDefault
====================
Decode BSON with MongoKitten Default
βββββββββββββββββββββββββββββββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ
β Metric β p0 β p25 β p50 β p75 β p90 β p99 β p100 β Samples β
βββββββββββββββββββββββββββββββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββ‘
β (Alloc + Retain) - Release Ξ * β 1476 β 1500 β 1506 β 1512 β 1520 β 1529 β 1536 β 376 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Object allocs * β 2334 β 2459 β 2493 β 2521 β 2545 β 2605 β 2634 β 376 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Releases (K) * β 21 β 21 β 22 β 22 β 22 β 22 β 22 β 376 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Retains (K) * β 17 β 18 β 18 β 18 β 18 β 18 β 18 β 376 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Throughput (# / s) (#) β 617 β 592 β 583 β 572 β 562 β 415 β 234 β 376 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Time (wall clock) (ΞΌs) * β 1620 β 1690 β 1714 β 1747 β 1781 β 2408 β 4276 β 376 β
βββββββββββββββββββββββββββββββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ
Decode BSON with This Library
βββββββββββββββββββββββββββββββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ
β Metric β p0 β p25 β p50 β p75 β p90 β p99 β p100 β Samples β
βββββββββββββββββββββββββββββββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββ‘
β (Alloc + Retain) - Release Ξ * β 7917 β 8035 β 8071 β 8099 β 8123 β 8167 β 8187 β 1000 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Object allocs * β 892 β 969 β 984 β 997 β 1011 β 1034 β 1061 β 1000 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Releases (K) * β 13 β 14 β 14 β 14 β 14 β 14 β 14 β 1000 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Retains * β 4406 β 4523 β 4555 β 4583 β 4607 β 4643 β 4697 β 1000 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Throughput (# / s) (#) β 1915 β 1820 β 1791 β 1748 β 1669 β 1175 β 1061 β 1000 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Time (wall clock) (ΞΌs) * β 522 β 549 β 559 β 572 β 599 β 810 β 943 β 1000 β
βββββββββββββββββββββββββββββββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ
Encode BSON with MongoKitten Default
βββββββββββββββββββββββββββββββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ
β Metric β p0 β p25 β p50 β p75 β p90 β p99 β p100 β Samples β
βββββββββββββββββββββββββββββββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββ‘
β (Alloc + Retain) - Release Ξ * β 5054 β 5247 β 5307 β 5379 β 5427 β 5519 β 5598 β 513 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Object allocs * β 2993 β 3113 β 3153 β 3199 β 3229 β 3279 β 3323 β 513 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Releases (K) * β 39 β 41 β 41 β 42 β 42 β 43 β 44 β 513 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Retains (K) * β 31 β 33 β 33 β 33 β 34 β 34 β 35 β 513 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Throughput (# / s) (#) β 198 β 189 β 185 β 182 β 177 β 162 β 132 β 513 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Time (wall clock) (ΞΌs) * β 5039 β 5300 β 5394 β 5501 β 5661 β 6181 β 7598 β 513 β
βββββββββββββββββββββββββββββββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ
Encode BSON with This Library
βββββββββββββββββββββββββββββββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ€ββββββββββ
β Metric β p0 β p25 β p50 β p75 β p90 β p99 β p100 β Samples β
βββββββββββββββββββββββββββββββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββͺββββββββββ‘
β (Alloc + Retain) - Release Ξ * β 5066 β 5251 β 5311 β 5375 β 5427 β 5531 β 5614 β 514 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Object allocs * β 3003 β 3123 β 3153 β 3199 β 3229 β 3293 β 3353 β 514 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Releases (K) * β 39 β 41 β 41 β 42 β 42 β 43 β 44 β 514 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Retains (K) * β 31 β 33 β 33 β 33 β 34 β 34 β 35 β 514 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Throughput (# / s) (#) β 198 β 189 β 186 β 183 β 178 β 159 β 95 β 514 β
βββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β Time (wall clock) (ΞΌs) * β 5061 β 5280 β 5366 β 5464 β 5612 β 6275 β 10509 β 514 β
βββββββββββββββββββββββββββββββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ§ββββββββββ
```
## Should I really be using BSON?
BSON is not for everyone. The rationales below are *not* good reasons to adopt BSON, at least by themselves.
### Saving disk space
BSON will save memory when parsing, but in typical use cases, a BSON file will occupy a similar amount of space as an equivalent JSON file, and offer a similar compression ratio.
### Serving to the web
BSON is generally considered a server side format, and there are few compelling reasons to synthesize it for the sole purpose of serving content to browsers.
That said, [JavaScript libraries](https://www.npmjs.com/package/bson) do exist for parsing BSON, so it is possible to use it on the client side. One good reason to do this is if you are storing BSON objects as static resources accessible from a CDN, and want clients to be able to download the BSON from the CDN instead of converting it dynamically to JSON via your HTTP server.
## Is it worth the effort?
Learning this library will enable you to use a high-performance binary serialization format across a wide range of platforms. The library is small, written in pure Swift, and organized around a few key patterns that emphasize maintainability in large codebases.
Although swift-bson cannot synthesize serialization code for you, its idioms are predictable and easily βpaintableβ by LLMs such as GitHub Copilot.
## What does the code look like?
In a βrealisticβ codebase, a BSON model type looks like this:
```swift
struct ExampleModel:BSONDocumentEncodable, BSONDocumentDecodable
{
let id:Int64
let name:String?
let rank:Rank
/// A custom enum type.
enum Rank:Int32, BSONEncodable, BSONDecodable
{
case newModel
case risingStar
case aspiringModel
case fashionista
case glamourista
case fashionMaven
case runwayQueen
case trendSetter
case runwayDiva
case topModel
}
/// The schema definition.
enum CodingKey:String, Sendable
{
case id = "_id" // Chosen for compatibility with MongoDB
case name = "D"
case rank = "R"
}
/// The serialization logic.
func encode(to bson:inout BSON.DocumentEncoder)
{
bson[.id] = self.id
bson[.name] = self.name
bson[.rank] = self.rank == .newModel ? nil : self.rank
}
/// The deserialization logic.
init(bson:BSON.DocumentDecoder) throws
{
self.id = try bson[.id].decode()
self.name = try bson[.name]?.decode()
self.rank = try bson[.rank]?.decode() ?? .newModel
}
}
```
The code to actually round-trip this to and from raw data looks like this:
```swift
let models:[ExampleModel] = [
.init(id: 0, name: "Gigi", rank: .topModel),
.init(id: 1, name: nil, rank: .newModel),
]
/// Round-trip one model
let document:BSON.Document = .init(encoding: models[0])
let _:ArraySlice = document.bytes
let model:ExampleModel = try .init(bson: document)
/// Round-trip a list of models
let list:BSON.List = .init(elements: models)
let _:ArraySlice = list.bytes
let array:[ExampleModel] = try .init(bson: list)
```
## Tutorials
- [Usage Examples](https://swiftinit.org/docs/swift-bson/bson/examples)
- [Protocols Explained](https://swiftinit.org/docs/swift-bson/bson/walkthrough)
- [Advanced Serialization Patterns](https://swiftinit.org/docs/swift-bson/bson/serialization-patterns)
- [Textures and Coordinates](https://swiftinit.org/docs/swift-bson/bson/textures-and-coordinates)
## License
The swift-bson library is Apache 2.0 licensed.