SpacetimeDB

0.23.0

avias8/spacetimedb-swift

What's New

SpacetimeDB Swift SDK 0.23.0

2026-07-17T14:47:23Z

Full Changelog: v0.22.0...v0.23.0

SpacetimeDB Swift SDK

Native Swift SDK for connecting to SpacetimeDB over v2.bsatn.spacetimedb, decoding realtime updates, and maintaining a typed local cache.

Swift Package Index Swift Versions Platforms

Contents

Requirements

  • Swift tools 6.2
  • Apple platforms:
    • macOS 15+
    • iOS 18+
    • visionOS 2+
    • watchOS 11+

Package Layout

spacetimedb-swift
├── Package.swift
├── Benchmarks/Package.swift
├── Sources/SpacetimeDB
│   ├── Auth/KeychainTokenStore.swift
│   ├── BSATN/
│   ├── Cache/
│   ├── Network/
│   ├── Log.swift
│   ├── RuntimeTypes.swift
│   └── SpacetimeDB.swift
└── Tests/SpacetimeDBTests

Add The SDK To A Swift Package

From GitHub releases (recommended):

dependencies: [
    .package(url: "https://github.com/avias8/spacetimedb-swift.git", from: "0.23.0"),
],
targets: [
    .executableTarget(
        name: "MyClient",
        dependencies: [
            .product(name: "SpacetimeDB", package: "spacetimedb-swift"),
        ]
    ),
]

From a local checkout:

dependencies: [
    .package(path: "../spacetimedb-swift"),
],
targets: [
    .executableTarget(
        name: "MyClient",
        dependencies: [
            .product(name: "SpacetimeDB", package: "spacetimedb-swift"),
        ]
    ),
]

Then import in code:

import SpacetimeDB

Quick Start

import Foundation
import SpacetimeDB

@MainActor
final class AppModel: SpacetimeClientDelegate {
    private var client: SpacetimeClient?

    func start() {
        SpacetimeModule.registerTables()

        let client = SpacetimeClient(
            serverUrl: URL(string: "http://127.0.0.1:3000")!,
            moduleName: "my-module"
        )
        client.delegate = self
        client.connect()
        self.client = client
    }

    func stop() {
        client?.disconnect()
        client = nil
    }

    // MARK: SpacetimeClientDelegate
    func onConnect() {}
    func onDisconnect(error: Error?) {}
    func onIdentityReceived(identity: [UInt8], token: String) {}
    func onTransactionUpdate(message: Data?) {}
    func onReducerError(reducer: String, message: String, isInternal: Bool) {}
}

Core API

Connect/Disconnect

let client = SpacetimeClient(serverUrl: url, moduleName: "my-module")
client.delegate = delegate
client.connect(token: optionalBearerToken)
client.disconnect()

Reducers

client.send("add_person", argsData)

Procedures

Typed callback:

client.sendProcedure("hello", argsData, responseType: String.self) { result in
    // Result<String, Error>
}

Raw callback:

client.sendProcedure("hello", argsData) { result in
    // Result<Data, Error>
}

async/await:

let rawData = try await client.sendProcedure("hello", argsData)
let value = try await client.sendProcedure("hello", argsData, responseType: String.self)
let timed = try await client.sendProcedure("hello", argsData, timeout: .seconds(5))
let typedTimed = try await client.sendProcedure("hello", argsData, responseType: String.self, timeout: .seconds(5))

One-Off Queries

Callback:

client.oneOffQuery("SELECT * FROM person") { result in
    // Result<QueryRows, Error>
}

async/await:

let rows = try await client.oneOffQuery("SELECT * FROM person")
let timedRows = try await client.oneOffQuery("SELECT * FROM person", timeout: .seconds(3))

Cancellation: cancel the task calling an async procedure/query API, and it throws CancellationError while removing the pending callback state.

Subscriptions

let handle = client.subscribe(
    queries: ["SELECT * FROM person"],
    onApplied: { /* initial snapshot applied */ },
    onError: { message in /* subscription failed */ }
)

handle.unsubscribe()

Client Cache

Register tables once, then read typed rows from generated caches:

SpacetimeModule.registerTables()
let people = PersonTable.cache.rows

The SDK applies transaction updates into SpacetimeClient.clientCache. Internal cache mutation remains off the main actor; observable rows snapshots are coalesced and published on the main actor for SwiftUI safety.

Auth Token Persistence (Keychain)

KeychainTokenStore provides opt-in token persistence per module:

let tokenStore = KeychainTokenStore(service: "com.example.myapp.spacetimedb")

// Load on app start.
let savedToken = tokenStore.load(forModule: "my-module")
client.connect(token: savedToken)

// Save when identity/token arrives.
func onIdentityReceived(identity: [UInt8], token: String) {
    tokenStore.save(token: token, forModule: "my-module")
}

Network Awareness And Reconnect Behavior

SpacetimeClient supports reconnect backoff through ReconnectPolicy:

let policy = ReconnectPolicy(
    maxRetries: nil,
    initialDelaySeconds: 1.0,
    maxDelaySeconds: 30.0,
    multiplier: 2.0,
    jitterRatio: 0.2
)

Network path changes are monitored internally. When the device is offline, reconnect attempts are deferred; when connectivity returns, reconnect is retriggered automatically.

Compression mode can be set at client construction:

let client = SpacetimeClient(
    serverUrl: url,
    moduleName: "my-module",
    reconnectPolicy: policy,
    compressionMode: .gzip // .none | .gzip | .brotli
)

Distribution Hardening

The Swift package is validated in CI for reproducibility and packaging health:

  • swift test
  • swift test --sanitize=thread
  • swift build -c release
  • iOS, visionOS, and watchOS simulator cross-builds
  • an isolated benchmark package that does not add dependencies to SDK consumers

DocC and Swift Package Index

DocC bundle and tutorials live in:

  • Sources/SpacetimeDB/SpacetimeDB.docc

DocC build command:

xcodebuild docbuild \
  -scheme SpacetimeDB \
  -destination 'generic/platform=macOS' \
  CODE_SIGNING_ALLOWED=NO

Swift Package Index builder config is in:

  • .spi.yml

Detailed publishing runbook:

  • PUBLISHING.md
  • DISTRIBUTION.md
  • SPI_SUBMISSION_CHECKLIST.md

Package page and badge endpoints:

Package: https://swiftpackageindex.com/avias8/spacetimedb-swift
Swift versions badge: https://img.shields.io/endpoint?url=https://swiftpackageindex.com/api/packages/avias8/spacetimedb-swift/badge?type=swift-versions
Platforms badge: https://img.shields.io/endpoint?url=https://swiftpackageindex.com/api/packages/avias8/spacetimedb-swift/badge?type=platforms

Apple CI Matrix

Swift CI runs from .github/workflows/ci.yml:

  • macOS: build, unit tests, Thread Sanitizer, and DocC
  • iOS simulator: cross-build of SpacetimeDB
  • visionOS simulator: cross-build of SpacetimeDB
  • watchOS simulator: cross-build of SpacetimeDB

Logging

The SDK uses os.Logger categories:

  • Client
  • Cache
  • Network

Logs are visible in Console.app and device logs using subsystem com.clockworklabs.SpacetimeDB.

Benchmarks

Benchmark target: SpacetimeDBBenchmarks

Includes suites for:

  • BSATN encode/decode
  • protocol message encode/decode
  • reducer/procedure request+response round-trip encode/decode
  • cache insert/delete throughput

Run from repo root:

swift package --package-path Benchmarks benchmark --target SpacetimeDBBenchmarks

List available benchmarks:

swift package --package-path Benchmarks benchmark list

Compare two captured baselines:

swift package --package-path Benchmarks benchmark baseline compare \
  <baseline-a> <baseline-b> \
  --target SpacetimeDBBenchmarks \
  --no-progress

Validation Matrix

From repo root:

swift test
swift test --sanitize=thread
swift build -c release
swift package --package-path Benchmarks benchmark list
swift package --package-path Benchmarks benchmark --target SpacetimeDBBenchmarks
xcodebuild docbuild -scheme SpacetimeDB -destination 'generic/platform=macOS' CODE_SIGNING_ALLOWED=NO

License

This package carries the SpacetimeDB Business Source License 1.1 terms in LICENSE.txt. Review that file before production use.

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

  • None
Last updated: Wed Oct 28 2026 02:09:24 GMT-0900 (Hawaii-Aleutian Daylight Time)