diff --git a/client-sdks/reference/swift.mdx b/client-sdks/reference/swift.mdx
index 0a573fc4..99691b0e 100644
--- a/client-sdks/reference/swift.mdx
+++ b/client-sdks/reference/swift.mdx
@@ -25,10 +25,11 @@ import LocalOnly from '/snippets/local-only-escape.mdx';
-## Kotlin -> Swift SDK
-
-The PowerSync Swift SDK makes use of the [PowerSync Kotlin SDK](https://github.com/powersync-ja/powersync-kotlin) with the API tool [SKIE](https://skie.touchlab.co/) under the hood to help generate and publish a Swift package. The Swift SDK abstracts the Kotlin SDK behind pure Swift Protocols, enabling us to fully leverage Swift's native features and libraries. Our ultimate goal is to deliver a Swift-centric experience for developers.
-
+
+ Earlier versions of the Swift SDK (up to v1.13) shipped a PowerSync Kotlin XCFramework under the hood and abstracted it behind Swift protocols.
+
+ From v1.14 onward, the Kotlin dependency has been removed entirely. The SDK is now implemented natively in Swift, with the PowerSync sync protocol and SQLite extension handled by our [Rust core](https://github.com/powersync-ja/powersync-sqlite-core).
+
### SDK Features
@@ -295,4 +296,8 @@ See [Supported Platforms -> Swift SDK](/resources/supported-platforms#swift-sdk)
## Upgrading the SDK
-Update the version number in `Package.swift` or via Xcode Package Dependencies as documented in the installation instructions: [Installation](/client-sdks/reference/swift#installation)
+Update the version number in `Package.swift` or via Xcode Package Dependencies as documented in the installation instructions: [Installation](/client-sdks/reference/swift#installation).
+
+
+ **Upgrading to v1.14**: This release removes the internal Kotlin dependency and re-implements the SQLite connection pool logic natively in Swift. The public API is unchanged, but the internals are a full rewrite. We recommend testing queries in your app after upgrading to this version.
+
diff --git a/client-sdks/usage-examples.mdx b/client-sdks/usage-examples.mdx
index 7413b46c..09c4863b 100644
--- a/client-sdks/usage-examples.mdx
+++ b/client-sdks/usage-examples.mdx
@@ -618,23 +618,28 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call
```swift
class MyConnector: PowerSyncBackendConnector {
override func uploadData(database: PowerSyncDatabaseProtocol) async throws {
- let batch = try await database.getCrudBatch()
- guard let batch = batch else { return }
+ guard let batch = try await database.getCrudBatch() else { return }
for entry in batch.crud {
switch entry.op {
case .put:
// Send the data to your backend service
// Replace `_myApi` with your own API client or service
- try await _myApi.put(table: entry.table, data: entry.opData)
+ // `opDataTyped` preserves SQLite types as a `[String: JsonValue]` dictionary.
+ // Use `opData` for the legacy `[String: String?]` representation.
+ try await _myApi.put(table: entry.table, data: entry.opDataTyped ?? [:])
default:
// TODO: implement the other operations (patch, delete)
break
}
}
- try await batch.complete(writeCheckpoint: nil)
+ try await batch.complete()
}
}
```
+
+
+ As of v1.14, `CrudBatch`, `CrudEntry`, and `CrudTransaction` are concrete `struct`s instead of protocols. Existing code that reads their properties continues to work unchanged, but they can no longer be constructed in user code (for example, in tests or mocks).
+
diff --git a/sync/streams/client-usage.mdx b/sync/streams/client-usage.mdx
index 6d0cf50e..a5110092 100644
--- a/sync/streams/client-usage.mdx
+++ b/sync/streams/client-usage.mdx
@@ -641,13 +641,69 @@ try await db.connect(
```csharp
-await db.Connect(connector, new ConnectOptions {
+await db.Connect(connector, new PowerSyncConnectionOptions {
Params = new() { ["environment"] = "production" }
});
```
+## Opting Out of Auto-Subscribed Streams
+
+By default, every stream defined with [`auto_subscribe: true`](/sync/streams/overview#using-auto-subscribe) starts syncing as soon as the client connects. For advanced use cases where the client needs more control over what syncs at connect time, you can set `includeDefaultStreams: false` on the connect options. The `auto_subscribe: true` flag is then ignored for that connection, and those streams only sync if the client explicitly calls `db.syncStream(name, params).subscribe()`.
+
+Most apps will not need this option. Defining streams without `auto_subscribe: true` and subscribing on-demand from the client generally achieves a similar result with less indirection. One scenario where it can help is during a migration from auto-subscribed streams to on-demand subscriptions. You keep the auto-subscribed streams in place so older client versions continue to sync correctly, while newer versions that explicitly subscribe to the streams they need set `includeDefaultStreams: false` to skip those defaults.
+
+
+
+
+```js
+// Connect without syncing auto_subscribe streams
+await db.connect(connector, {
+ includeDefaultStreams: false
+});
+
+// Later, opt in to a specific stream
+const sub = await db.syncStream('my_stream', params).subscribe();
+```
+
+
+
+```dart
+await db.connect(
+ connector: connector,
+ options: const SyncOptions(includeDefaultStreams: false),
+);
+```
+
+
+
+```kotlin
+database.connect(
+ connector,
+ options = SyncOptions(includeDefaultStreams = false)
+)
+```
+
+
+
+```swift
+try await db.connect(
+ connector: connector,
+ options: ConnectOptions(includeDefaultStreams: false)
+)
+```
+
+
+
+```csharp
+await db.Connect(connector, new PowerSyncConnectionOptions {
+ IncludeDefaultStreams = false
+});
+```
+
+
+
## API Reference
For quick reference, here are the key methods available in each SDK:
diff --git a/sync/streams/migration.mdx b/sync/streams/migration.mdx
index 8df67f40..a16077f2 100644
--- a/sync/streams/migration.mdx
+++ b/sync/streams/migration.mdx
@@ -88,7 +88,7 @@ database.connect(MyConnector(), options = SyncOptions(
**Swift:**
```swift
-@_spi(PowerSyncExperimental) import PowerSync
+import PowerSync
try await db.connect(connector: connector, options: ConnectOptions(
newClientImplementation: true,