From 13abc083bc78b244e88223ccab3dc93046f4fb2e Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:07:48 +0200 Subject: [PATCH 1/7] Add a 'subscribe to sync streams' section to SDK reference - Flutter --- client-sdks/reference/flutter.mdx | 15 ++++++++++++++- snippets/flutter/subscribe-sync-stream.mdx | 13 +++++++++++++ snippets/subscribe-sync-streams-intro.mdx | 1 + snippets/subscribe-sync-streams-outro.mdx | 1 + sync/streams/client-usage.mdx | 16 +++------------- 5 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 snippets/flutter/subscribe-sync-stream.mdx create mode 100644 snippets/subscribe-sync-streams-intro.mdx create mode 100644 snippets/subscribe-sync-streams-outro.mdx diff --git a/client-sdks/reference/flutter.mdx b/client-sdks/reference/flutter.mdx index bd6c6aa1a..545c3b34c 100644 --- a/client-sdks/reference/flutter.mdx +++ b/client-sdks/reference/flutter.mdx @@ -9,6 +9,9 @@ import FlutterInstallation from '/snippets/flutter/installation.mdx'; import FlutterWatch from '/snippets/flutter/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import FlutterSubscribeSyncStream from '/snippets/flutter/subscribe-sync-stream.mdx'; ```text Build with AI icon="sparkles" wrap Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skills. Then follow the skills to onboard this project to PowerSync using the Dart/Flutter SDK. @@ -250,9 +253,19 @@ class MyBackendConnector extends PowerSyncBackendConnector { ``` +### 4\. Subscribe to Sync Streams + + + +Sync Streams require `powersync` version 1.16.0 or later. + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/snippets/flutter/subscribe-sync-stream.mdx b/snippets/flutter/subscribe-sync-stream.mdx new file mode 100644 index 000000000..ba26a08f5 --- /dev/null +++ b/snippets/flutter/subscribe-sync-stream.mdx @@ -0,0 +1,13 @@ +```dart +// Subscribe to a stream with parameters +final sub = await db.syncStream('list_todos', {'list_id': 'abc123'}).subscribe(); + +// Wait for the initial data to sync +await sub.waitForFirstSync(); + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data +sub.unsubscribe(); +``` diff --git a/snippets/subscribe-sync-streams-intro.mdx b/snippets/subscribe-sync-streams-intro.mdx new file mode 100644 index 000000000..a5d6ab140 --- /dev/null +++ b/snippets/subscribe-sync-streams-intro.mdx @@ -0,0 +1 @@ +Streams defined with `auto_subscribe: true` start syncing as soon as the client connects. For all other streams, your app must subscribe before their data downloads. The basic pattern is: subscribe to a stream, wait for its data to sync, then unsubscribe when the screen no longer needs the data. diff --git a/snippets/subscribe-sync-streams-outro.mdx b/snippets/subscribe-sync-streams-outro.mdx new file mode 100644 index 000000000..1da1c9516 --- /dev/null +++ b/snippets/subscribe-sync-streams-outro.mdx @@ -0,0 +1 @@ +After you unsubscribe, the synced data stays in the local database for the stream's TTL (24 hours by default). If the app subscribes again within that time, the data is already available. Framework hooks, per-subscription sync status, custom TTLs, priority overrides, and connection parameters are covered in [Client-Side Usage](/sync/streams/client-usage). diff --git a/sync/streams/client-usage.mdx b/sync/streams/client-usage.mdx index b61271770..84eb8bc51 100644 --- a/sync/streams/client-usage.mdx +++ b/sync/streams/client-usage.mdx @@ -3,6 +3,8 @@ title: "Client-Side Usage" description: "Subscribe to Sync Streams from your client app and manage subscriptions dynamically." --- +import FlutterSubscribeSyncStream from '/snippets/flutter/subscribe-sync-stream.mdx'; + After [defining your streams](/sync/streams/overview#defining-streams) on the server-side, your client app subscribes to them to start syncing data (this is an explicit operation unless streams are configured to [auto-subscribe](/sync/streams/overview#using-auto-subscribe)). This page covers everything you need to use Sync Streams from your client code. ## Quick Start @@ -34,19 +36,7 @@ sub.unsubscribe(); -```dart -// Subscribe to a stream with parameters -final sub = await db.syncStream('list_todos', {'list_id': 'abc123'}).subscribe(); - -// Wait for initial data to sync -await sub.waitForFirstSync(); - -// Your data is now available - query it normally -final todos = await db.getAll('SELECT * FROM todos WHERE list_id = ?', ['abc123']); - -// When leaving the screen or component... -sub.unsubscribe(); -``` + From fc54a7d5c85c6b8f899c4081908f8f5ee88406a7 Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:14:30 +0200 Subject: [PATCH 2/7] Do the same for JS SDK references --- client-sdks/reference/capacitor.mdx | 13 ++++++++++++- client-sdks/reference/flutter.mdx | 2 -- client-sdks/reference/javascript-web.mdx | 15 ++++++++++++++- client-sdks/reference/node.mdx | 13 ++++++++++++- client-sdks/reference/react-native-and-expo.mdx | 15 ++++++++++++++- client-sdks/reference/tauri.mdx | 13 ++++++++++++- snippets/javascript/subscribe-sync-stream.mdx | 13 +++++++++++++ sync/streams/client-usage.mdx | 15 ++------------- 8 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 snippets/javascript/subscribe-sync-stream.mdx diff --git a/client-sdks/reference/capacitor.mdx b/client-sdks/reference/capacitor.mdx index 93ecaa19c..9295332eb 100644 --- a/client-sdks/reference/capacitor.mdx +++ b/client-sdks/reference/capacitor.mdx @@ -10,6 +10,9 @@ import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.m import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; ```text Build with AI icon="sparkles" wrap @@ -221,9 +224,17 @@ export class Connector { } ``` +### 4. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. **All CRUD examples from the JavaScript Web SDK apply**: The Capacitor SDK uses the same API as the Web SDK. See the [JavaScript Web SDK CRUD functions section](/client-sdks/reference/javascript-web#using-powersync-crud-functions) for examples of `get`, `getAll`, `watch`, `execute`, `writeTransaction`, incremental watch updates, and differential results. diff --git a/client-sdks/reference/flutter.mdx b/client-sdks/reference/flutter.mdx index 545c3b34c..4f4ea16de 100644 --- a/client-sdks/reference/flutter.mdx +++ b/client-sdks/reference/flutter.mdx @@ -257,8 +257,6 @@ class MyBackendConnector extends PowerSyncBackendConnector { -Sync Streams require `powersync` version 1.16.0 or later. - diff --git a/client-sdks/reference/javascript-web.mdx b/client-sdks/reference/javascript-web.mdx index f866e07f4..fff3931ea 100644 --- a/client-sdks/reference/javascript-web.mdx +++ b/client-sdks/reference/javascript-web.mdx @@ -9,6 +9,9 @@ import JavaScriptWebInstallation from '/snippets/javascript-web/installation.mdx import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; @@ -206,9 +209,19 @@ export class Connector { } ``` +### 4. Subscribe to Sync Streams + + + + + +If you use React, the `useQuery` hook accepts a `streams` option and the `useSyncStream` hook manages a subscription for you. See [Framework Integrations](/sync/streams/client-usage#framework-integrations). + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/client-sdks/reference/node.mdx b/client-sdks/reference/node.mdx index 8ac1121e7..9f7428684 100644 --- a/client-sdks/reference/node.mdx +++ b/client-sdks/reference/node.mdx @@ -10,6 +10,9 @@ import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.m import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; @@ -142,9 +145,17 @@ await db.waitForFirstSync(); // Optional, to wait for a complete snapshot of dat +### 4. Subscribe to Sync Streams + + + + + + + ## Usage -After connecting the client database, it is ready to be used. The API to run queries and updates is identical to our +Once the database is connected and your streams have synced, the data is in the local SQLite database. The API to run queries and updates is identical to our [JavaScript/Web SDK](/client-sdks/reference/javascript-web#using-powersync-crud-functions): ```js diff --git a/client-sdks/reference/react-native-and-expo.mdx b/client-sdks/reference/react-native-and-expo.mdx index 93194c50a..c40478ea4 100644 --- a/client-sdks/reference/react-native-and-expo.mdx +++ b/client-sdks/reference/react-native-and-expo.mdx @@ -10,6 +10,9 @@ import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.m import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; ```text Build with AI icon="sparkles" wrap @@ -216,9 +219,19 @@ export class Connector implements PowerSyncBackendConnector { } ``` +### 4\. Subscribe to Sync Streams + + + + + +If you use React, the `useQuery` hook accepts a `streams` option and the `useSyncStream` hook manages a subscription for you. See [Framework Integrations](/sync/streams/client-usage#framework-integrations). + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/client-sdks/reference/tauri.mdx b/client-sdks/reference/tauri.mdx index 96ce9d42d..aec700887 100644 --- a/client-sdks/reference/tauri.mdx +++ b/client-sdks/reference/tauri.mdx @@ -10,6 +10,9 @@ import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.m import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; ```text Build with AI icon="sparkles" wrap Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skills. Then follow the skills to onboard this project to PowerSync using the Tauri SDK. @@ -230,9 +233,17 @@ impl BackendConnector for MyBackendConnector { } ``` +### 4. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. **All CRUD examples from the JavaScript Web SDK apply**: The Tauri SDK exposes the same JavaScript database API as the Web SDK. See the [JavaScript Web SDK CRUD functions section](/client-sdks/reference/javascript-web#using-powersync-crud-functions) for examples of `get`, `getAll`, `watch`, `execute`, `writeTransaction`, incremental watch updates, and differential results. diff --git a/snippets/javascript/subscribe-sync-stream.mdx b/snippets/javascript/subscribe-sync-stream.mdx new file mode 100644 index 000000000..80d0a69a9 --- /dev/null +++ b/snippets/javascript/subscribe-sync-stream.mdx @@ -0,0 +1,13 @@ +```js +// Subscribe to a stream with parameters +const sub = await db.syncStream('list_todos', { list_id: 'abc123' }).subscribe(); + +// Wait for the initial data to sync +await sub.waitForFirstSync(); + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data +sub.unsubscribe(); +``` diff --git a/sync/streams/client-usage.mdx b/sync/streams/client-usage.mdx index 84eb8bc51..13ac680c6 100644 --- a/sync/streams/client-usage.mdx +++ b/sync/streams/client-usage.mdx @@ -3,6 +3,7 @@ title: "Client-Side Usage" description: "Subscribe to Sync Streams from your client app and manage subscriptions dynamically." --- +import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import FlutterSubscribeSyncStream from '/snippets/flutter/subscribe-sync-stream.mdx'; After [defining your streams](/sync/streams/overview#defining-streams) on the server-side, your client app subscribes to them to start syncing data (this is an explicit operation unless streams are configured to [auto-subscribe](/sync/streams/overview#using-auto-subscribe)). This page covers everything you need to use Sync Streams from your client code. @@ -20,19 +21,7 @@ For any other streams, the basic pattern is: **subscribe** to a stream, **wait** **Tauri SDK**: The JavaScript API shown in the TypeScript/JavaScript tabs throughout this page applies to Tauri as well. Import from `@powersync/tauri-plugin` (for `PowerSyncTauriDatabase`) or `@powersync/common` (for shared types). See the [Connection Parameters](#connection-parameters) section below for how Tauri handles connect-time parameters differently. -```js -// Subscribe to a stream with parameters -const sub = await db.syncStream('list_todos', { list_id: 'abc123' }).subscribe(); - -// Wait for initial data to sync -await sub.waitForFirstSync(); - -// Your data is now available - query it normally -const todos = await db.getAll('SELECT * FROM todos WHERE list_id = ?', ['abc123']); - -// When leaving the screen or component... -sub.unsubscribe(); -``` + From 73fcdce14ac4d42c78c9c2d26637945436c94f34 Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:19:11 +0200 Subject: [PATCH 3/7] Also for Kotlin, .NET and Swift --- client-sdks/reference/dotnet.mdx | 13 ++++++- client-sdks/reference/kotlin.mdx | 13 ++++++- client-sdks/reference/swift.mdx | 13 ++++++- snippets/dotnet/subscribe-sync-stream.mdx | 13 +++++++ snippets/kotlin/subscribe-sync-stream.mdx | 14 +++++++ snippets/swift/subscribe-sync-stream.mdx | 13 +++++++ sync/streams/client-usage.mdx | 46 +++-------------------- 7 files changed, 82 insertions(+), 43 deletions(-) create mode 100644 snippets/dotnet/subscribe-sync-stream.mdx create mode 100644 snippets/kotlin/subscribe-sync-stream.mdx create mode 100644 snippets/swift/subscribe-sync-stream.mdx diff --git a/client-sdks/reference/dotnet.mdx b/client-sdks/reference/dotnet.mdx index dce36c93b..04759745a 100644 --- a/client-sdks/reference/dotnet.mdx +++ b/client-sdks/reference/dotnet.mdx @@ -9,6 +9,9 @@ import DotNetInstallation from '/snippets/dotnet/installation.mdx'; import DotNetWatch from '/snippets/dotnet/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import DotnetSubscribeSyncStream from '/snippets/dotnet/subscribe-sync-stream.mdx'; ```text Build with AI icon="sparkles" wrap Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skills. Then follow the skills to onboard this project to PowerSync using the .NET SDK. @@ -335,9 +338,17 @@ await db.WaitForFirstSync(); // Optional, to wait for a complete snapshot of dat +### 4. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/client-sdks/reference/kotlin.mdx b/client-sdks/reference/kotlin.mdx index 147559d45..ff158236b 100644 --- a/client-sdks/reference/kotlin.mdx +++ b/client-sdks/reference/kotlin.mdx @@ -9,6 +9,9 @@ import KotlinInstallation from '/snippets/kotlin/installation.mdx'; import KotlinWatch from '/snippets/kotlin/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import KotlinSubscribeSyncStream from '/snippets/kotlin/subscribe-sync-stream.mdx'; ```text Build with AI icon="sparkles" wrap Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skills. Then follow the skills to onboard this project to PowerSync using the Kotlin Multiplatform SDK. @@ -201,9 +204,17 @@ class MyConnector : PowerSyncBackendConnector() { **Note**: If you are using Supabase, you can use [SupabaseConnector.kt](https://github.com/powersync-ja/powersync-kotlin/blob/main/integrations/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt) as a starting point. +### 4\. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/client-sdks/reference/swift.mdx b/client-sdks/reference/swift.mdx index d67c19cce..2fe063b19 100644 --- a/client-sdks/reference/swift.mdx +++ b/client-sdks/reference/swift.mdx @@ -9,6 +9,9 @@ import SwiftInstallation from '/snippets/swift/installation.mdx'; import SwiftWatch from '/snippets/swift/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import SwiftSubscribeSyncStream from '/snippets/swift/subscribe-sync-stream.mdx'; ```text Build with AI icon="sparkles" wrap Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skills. Then follow the skills to onboard this project to PowerSync using the Swift SDK. @@ -171,9 +174,17 @@ try await powerSync.connect(connector: connector) +### 4. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/snippets/dotnet/subscribe-sync-stream.mdx b/snippets/dotnet/subscribe-sync-stream.mdx new file mode 100644 index 000000000..b982529cd --- /dev/null +++ b/snippets/dotnet/subscribe-sync-stream.mdx @@ -0,0 +1,13 @@ +```csharp +// Subscribe to a stream with parameters +var sub = await db.SyncStream("list_todos", new() { ["list_id"] = "abc123" }).Subscribe(); + +// Wait for the initial data to sync +await sub.WaitForFirstSync(); + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data +sub.Unsubscribe(); +``` diff --git a/snippets/kotlin/subscribe-sync-stream.mdx b/snippets/kotlin/subscribe-sync-stream.mdx new file mode 100644 index 000000000..820511bff --- /dev/null +++ b/snippets/kotlin/subscribe-sync-stream.mdx @@ -0,0 +1,14 @@ +```kotlin +// Subscribe to a stream with parameters +val sub = database.syncStream("list_todos", mapOf("list_id" to JsonParam.String("abc123"))) + .subscribe() + +// Wait for the initial data to sync +sub.waitForFirstSync() + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data +sub.unsubscribe() +``` diff --git a/snippets/swift/subscribe-sync-stream.mdx b/snippets/swift/subscribe-sync-stream.mdx new file mode 100644 index 000000000..2de1a6abc --- /dev/null +++ b/snippets/swift/subscribe-sync-stream.mdx @@ -0,0 +1,13 @@ +```swift +// Subscribe to a stream with parameters +let sub = try await db.syncStream(name: "list_todos", params: ["list_id": .string("abc123")]).subscribe() + +// Wait for the initial data to sync +try await sub.waitForFirstSync() + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data +try await sub.unsubscribe() +``` diff --git a/sync/streams/client-usage.mdx b/sync/streams/client-usage.mdx index 13ac680c6..993f7499a 100644 --- a/sync/streams/client-usage.mdx +++ b/sync/streams/client-usage.mdx @@ -5,6 +5,9 @@ description: "Subscribe to Sync Streams from your client app and manage subscrip import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; import FlutterSubscribeSyncStream from '/snippets/flutter/subscribe-sync-stream.mdx'; +import KotlinSubscribeSyncStream from '/snippets/kotlin/subscribe-sync-stream.mdx'; +import SwiftSubscribeSyncStream from '/snippets/swift/subscribe-sync-stream.mdx'; +import DotnetSubscribeSyncStream from '/snippets/dotnet/subscribe-sync-stream.mdx'; After [defining your streams](/sync/streams/overview#defining-streams) on the server-side, your client app subscribes to them to start syncing data (this is an explicit operation unless streams are configured to [auto-subscribe](/sync/streams/overview#using-auto-subscribe)). This page covers everything you need to use Sync Streams from your client code. @@ -29,52 +32,15 @@ For any other streams, the basic pattern is: **subscribe** to a stream, **wait** -```kotlin -// Subscribe to a stream with parameters -val sub = database.syncStream("list_todos", mapOf("list_id" to JsonParam.String("abc123"))) - .subscribe() - -// Wait for initial data to sync -sub.waitForFirstSync() - -// Your data is now available - query it normally -val todos = database.getAll("SELECT * FROM todos WHERE list_id = ?", listOf("abc123")) - -// When leaving the screen or component... -sub.unsubscribe() -``` + -```swift -// Subscribe to a stream with parameters -let sub = try await db.syncStream(name: "list_todos", params: ["list_id": JsonValue.string("abc123")]).subscribe() - -// Wait for initial data to sync -try await sub.waitForFirstSync() - -// Your data is now available - query it normally -let todos = try await db.getAll(sql: "SELECT * FROM todos WHERE list_id = ?", parameters: ["abc123"]) - -// When leaving the screen or component... -try await sub.unsubscribe() -``` + -```csharp -// Subscribe to a stream with parameters -var sub = await db.SyncStream("list_todos", new() { ["list_id"] = "abc123" }).Subscribe(); - -// Wait for initial data to sync -await sub.WaitForFirstSync(); - -// Your data is now available - query it normally -var todos = await db.GetAll("SELECT * FROM todos WHERE list_id = ?", new[] { "abc123" }); - -// When leaving the screen or component... -sub.Unsubscribe(); -``` + From ea9edc939e6b675026cf0d687b4cb8171542d645 Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:30:33 +0200 Subject: [PATCH 4/7] Add Rust --- client-sdks/reference/rust.mdx | 13 ++++++++++++- snippets/rust/subscribe-sync-stream.mdx | 19 +++++++++++++++++++ sync/streams/client-usage.mdx | 5 +++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 snippets/rust/subscribe-sync-stream.mdx diff --git a/client-sdks/reference/rust.mdx b/client-sdks/reference/rust.mdx index 9273bc238..00460419e 100644 --- a/client-sdks/reference/rust.mdx +++ b/client-sdks/reference/rust.mdx @@ -9,6 +9,9 @@ import RustInstallation from '/snippets/rust/installation.mdx'; import RustWatchQuery from '/snippets/rust/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; +import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; +import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; +import RustSubscribeSyncStream from '/snippets/rust/subscribe-sync-stream.mdx'; This SDK is currently in [**alpha**](/resources/feature-status), intended for external testing and public feedback. Expect breaking changes and instability as development continues. @@ -296,9 +299,17 @@ impl BackendConnector for MyBackendConnector { } ``` +### 4\. Subscribe to Sync Streams + + + + + + + ## Using PowerSync: CRUD functions -Once the PowerSync instance is configured you can start using the SQLite DB functions. +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: diff --git a/snippets/rust/subscribe-sync-stream.mdx b/snippets/rust/subscribe-sync-stream.mdx new file mode 100644 index 000000000..46be2e039 --- /dev/null +++ b/snippets/rust/subscribe-sync-stream.mdx @@ -0,0 +1,19 @@ +```Rust +use serde_json::json; + +// Subscribe to a stream with parameters +let sub = db + .sync_stream("list_todos", Some(&json!({ "list_id": "abc123" }))) + .subscribe() + .await?; + +// Wait for the initial data to sync +sub.wait_for_first_sync().await; + +// The stream's rows are now in the local SQLite database. +// TODO: Read the todos for this list with a local query and render them. + +// When the screen no longer needs the data. +// Dropping the subscription handle has the same effect. +sub.unsubscribe(); +``` diff --git a/sync/streams/client-usage.mdx b/sync/streams/client-usage.mdx index 993f7499a..3c0658625 100644 --- a/sync/streams/client-usage.mdx +++ b/sync/streams/client-usage.mdx @@ -8,6 +8,7 @@ import FlutterSubscribeSyncStream from '/snippets/flutter/subscribe-sync-stream. import KotlinSubscribeSyncStream from '/snippets/kotlin/subscribe-sync-stream.mdx'; import SwiftSubscribeSyncStream from '/snippets/swift/subscribe-sync-stream.mdx'; import DotnetSubscribeSyncStream from '/snippets/dotnet/subscribe-sync-stream.mdx'; +import RustSubscribeSyncStream from '/snippets/rust/subscribe-sync-stream.mdx'; After [defining your streams](/sync/streams/overview#defining-streams) on the server-side, your client app subscribes to them to start syncing data (this is an explicit operation unless streams are configured to [auto-subscribe](/sync/streams/overview#using-auto-subscribe)). This page covers everything you need to use Sync Streams from your client code. @@ -42,6 +43,10 @@ For any other streams, the basic pattern is: **subscribe** to a stream, **wait** + + + + ## Framework Integrations From a8ecd831fdd48202a30ac878181364345fab993f Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:34:39 +0200 Subject: [PATCH 5/7] Remove mention of sync rules from the SDK references --- client-sdks/reference/capacitor.mdx | 6 +++--- client-sdks/reference/dotnet.mdx | 6 +++--- client-sdks/reference/flutter.mdx | 8 ++++---- client-sdks/reference/javascript-web.mdx | 6 +++--- client-sdks/reference/kotlin.mdx | 8 ++++---- client-sdks/reference/node.mdx | 6 +++--- client-sdks/reference/react-native-and-expo.mdx | 8 ++++---- client-sdks/reference/rust.mdx | 8 ++++---- client-sdks/reference/swift.mdx | 6 +++--- client-sdks/reference/tauri.mdx | 9 ++++----- snippets/generate-schema-automatically.mdx | 2 +- snippets/sdk-client-side-schema.mdx | 2 +- 12 files changed, 37 insertions(+), 38 deletions(-) diff --git a/client-sdks/reference/capacitor.mdx b/client-sdks/reference/capacitor.mdx index 9295332eb..46ebb7318 100644 --- a/client-sdks/reference/capacitor.mdx +++ b/client-sdks/reference/capacitor.mdx @@ -64,7 +64,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -74,7 +74,7 @@ import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -124,7 +124,7 @@ export type ListRecord = Database['lists']; ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/dotnet.mdx b/client-sdks/reference/dotnet.mdx index 04759745a..272e04052 100644 --- a/client-sdks/reference/dotnet.mdx +++ b/client-sdks/reference/dotnet.mdx @@ -67,7 +67,7 @@ For more details, please refer to the package [README](https://github.com/powers -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -79,7 +79,7 @@ import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; You can use [this example](https://github.com/powersync-ja/powersync-dotnet/blob/main/demos/CommandLine/AppSchema.cs) as a reference when defining your schema. -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). #### Schema Definition Syntax @@ -149,7 +149,7 @@ var todos = await db.GetAll("SELECT * FROM todos"); ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/flutter.mdx b/client-sdks/reference/flutter.mdx index 4f4ea16de..0f3b1e35f 100644 --- a/client-sdks/reference/flutter.mdx +++ b/client-sdks/reference/flutter.mdx @@ -56,7 +56,7 @@ Get started quickly by using the self-hosted **Flutter** + **Supabase** template ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). For this reference document, we assume that you have created a Flutter project and have the following directory structure: @@ -78,11 +78,11 @@ lib/ ### 1\. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). +The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -116,7 +116,7 @@ const schema = Schema(([ ### 2\. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. To instantiate `PowerSyncDatabase`, inject the Schema you defined in the previous step and a file path — it's important to only instantiate one instance of `PowerSyncDatabase` per file. diff --git a/client-sdks/reference/javascript-web.mdx b/client-sdks/reference/javascript-web.mdx index fff3931ea..28043b060 100644 --- a/client-sdks/reference/javascript-web.mdx +++ b/client-sdks/reference/javascript-web.mdx @@ -83,7 +83,7 @@ The PowerSync [JavaScript Web SDK](../javascript-web) is compatible with popular ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -93,7 +93,7 @@ import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -139,7 +139,7 @@ export type ListRecord = Database['lists']; ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/kotlin.mdx b/client-sdks/reference/kotlin.mdx index ff158236b..871de6839 100644 --- a/client-sdks/reference/kotlin.mdx +++ b/client-sdks/reference/kotlin.mdx @@ -52,15 +52,15 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1\. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). +The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -107,7 +107,7 @@ val AppSchema: Schema = Schema( ### 2\. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/node.mdx b/client-sdks/reference/node.mdx index 9f7428684..dcb25c879 100644 --- a/client-sdks/reference/node.mdx +++ b/client-sdks/reference/node.mdx @@ -55,7 +55,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -67,13 +67,13 @@ You can use [this example](https://github.com/powersync-ja/powersync-js/blob/e5a -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). Select JavaScript and replace the suggested import with `@powersync/node`. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/react-native-and-expo.mdx b/client-sdks/reference/react-native-and-expo.mdx index c40478ea4..1f4f60a52 100644 --- a/client-sdks/reference/react-native-and-expo.mdx +++ b/client-sdks/reference/react-native-and-expo.mdx @@ -59,15 +59,15 @@ A separate `powersync-react` package is available containing React hooks for Pow ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1\. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). +The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -112,7 +112,7 @@ export type ListRecord = Database['lists']; ### 2\. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/rust.mdx b/client-sdks/reference/rust.mdx index 00460419e..70474fb47 100644 --- a/client-sdks/reference/rust.mdx +++ b/client-sdks/reference/rust.mdx @@ -49,15 +49,15 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1\. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). +The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -101,7 +101,7 @@ pub fn app_schema() -> Schema { ### 2\. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. #### Process Setup diff --git a/client-sdks/reference/swift.mdx b/client-sdks/reference/swift.mdx index 2fe063b19..dbf037885 100644 --- a/client-sdks/reference/swift.mdx +++ b/client-sdks/reference/swift.mdx @@ -47,7 +47,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -57,7 +57,7 @@ import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). **Example**: @@ -111,7 +111,7 @@ let AppSchema = Schema(lists, todos) ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: diff --git a/client-sdks/reference/tauri.mdx b/client-sdks/reference/tauri.mdx index aec700887..636380fe3 100644 --- a/client-sdks/reference/tauri.mdx +++ b/client-sdks/reference/tauri.mdx @@ -55,7 +55,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (or legacy Sync Rules) (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). ### 1. Define the Client-Side Schema @@ -65,7 +65,7 @@ import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). The Tauri SDK inherits the same APIs from the JavaScript Web SDK via `@powersync/common`, with a few exceptions detailed below. See the [Web SDK schema definition section](/client-sdks/reference/javascript-web#1-define-the-client-side-schema) for more advanced examples. @@ -115,7 +115,7 @@ export type ListRecord = Database['lists']; ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview) (or legacy [Sync Rules](/sync/rules/overview)). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. **Example**: @@ -337,8 +337,7 @@ Connection locks and table updates are automatically shared between Rust and Jav ## Limitations -- The Rust SDK, which is used to implement the Tauri plugin, has limited support for legacy Sync Rules: - On `SyncStatus`, `lastSyncedAt`, `hasSynced` and `priorityStatusEntries` are not available. +- The Rust SDK, which is used to implement the Tauri plugin, does not provide `lastSyncedAt`, `hasSynced` and `priorityStatusEntries` on `SyncStatus`. Use the status on individual Sync Streams through `SyncStatus.forStream` instead. - Connecting to the PowerSync Service is only possible from Rust. Calling `connect()` from JavaScript will throw. diff --git a/snippets/generate-schema-automatically.mdx b/snippets/generate-schema-automatically.mdx index b56deea0c..91e0f20f6 100644 --- a/snippets/generate-schema-automatically.mdx +++ b/snippets/generate-schema-automatically.mdx @@ -1,7 +1,7 @@ **Generate schema automatically** - In the [PowerSync Dashboard](https://dashboard.powersync.com/), select your project and instance and click the **Connect** button in the top bar to generate the client-side schema in your preferred language. The schema will be generated based off your Sync Streams/Rules. + In the [PowerSync Dashboard](https://dashboard.powersync.com/), select your project and instance and click the **Connect** button in the top bar to generate the client-side schema in your preferred language. The schema will be generated based on your Sync Streams. Similar functionality exists in the [CLI](/tools/cli). diff --git a/snippets/sdk-client-side-schema.mdx b/snippets/sdk-client-side-schema.mdx index 9b9c5c2f7..a922d247b 100644 --- a/snippets/sdk-client-side-schema.mdx +++ b/snippets/sdk-client-side-schema.mdx @@ -1 +1 @@ -This refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The schema is applied when the database is instantiated (as we'll show in the next step) — no migrations are required. \ No newline at end of file +This refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The schema is applied when the database is instantiated (as we'll show in the next step) — no migrations are required. \ No newline at end of file From 74b095b28f1688a30711145f1ecc425fe79d48c8 Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:37:30 +0200 Subject: [PATCH 6/7] Polish --- snippets/dotnet/subscribe-sync-stream.mdx | 4 ++-- snippets/flutter/subscribe-sync-stream.mdx | 4 ++-- snippets/javascript/subscribe-sync-stream.mdx | 4 ++-- snippets/kotlin/subscribe-sync-stream.mdx | 4 ++-- snippets/rust/subscribe-sync-stream.mdx | 4 ++-- snippets/subscribe-sync-streams-intro.mdx | 2 +- snippets/swift/subscribe-sync-stream.mdx | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/snippets/dotnet/subscribe-sync-stream.mdx b/snippets/dotnet/subscribe-sync-stream.mdx index b982529cd..0842f1630 100644 --- a/snippets/dotnet/subscribe-sync-stream.mdx +++ b/snippets/dotnet/subscribe-sync-stream.mdx @@ -6,8 +6,8 @@ var sub = await db.SyncStream("list_todos", new() { ["list_id"] = "abc123" }).Su await sub.WaitForFirstSync(); // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data +// When the data is no longer needed sub.Unsubscribe(); ``` diff --git a/snippets/flutter/subscribe-sync-stream.mdx b/snippets/flutter/subscribe-sync-stream.mdx index ba26a08f5..00dfcf420 100644 --- a/snippets/flutter/subscribe-sync-stream.mdx +++ b/snippets/flutter/subscribe-sync-stream.mdx @@ -6,8 +6,8 @@ final sub = await db.syncStream('list_todos', {'list_id': 'abc123'}).subscribe() await sub.waitForFirstSync(); // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data +// When the data is no longer needed sub.unsubscribe(); ``` diff --git a/snippets/javascript/subscribe-sync-stream.mdx b/snippets/javascript/subscribe-sync-stream.mdx index 80d0a69a9..e9dce3042 100644 --- a/snippets/javascript/subscribe-sync-stream.mdx +++ b/snippets/javascript/subscribe-sync-stream.mdx @@ -6,8 +6,8 @@ const sub = await db.syncStream('list_todos', { list_id: 'abc123' }).subscribe() await sub.waitForFirstSync(); // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data +// When the data is no longer needed sub.unsubscribe(); ``` diff --git a/snippets/kotlin/subscribe-sync-stream.mdx b/snippets/kotlin/subscribe-sync-stream.mdx index 820511bff..d1c8521c0 100644 --- a/snippets/kotlin/subscribe-sync-stream.mdx +++ b/snippets/kotlin/subscribe-sync-stream.mdx @@ -7,8 +7,8 @@ val sub = database.syncStream("list_todos", mapOf("list_id" to JsonParam.String( sub.waitForFirstSync() // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data +// When the data is no longer needed sub.unsubscribe() ``` diff --git a/snippets/rust/subscribe-sync-stream.mdx b/snippets/rust/subscribe-sync-stream.mdx index 46be2e039..35817619e 100644 --- a/snippets/rust/subscribe-sync-stream.mdx +++ b/snippets/rust/subscribe-sync-stream.mdx @@ -11,9 +11,9 @@ let sub = db sub.wait_for_first_sync().await; // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data. +// When the data is no longer needed. // Dropping the subscription handle has the same effect. sub.unsubscribe(); ``` diff --git a/snippets/subscribe-sync-streams-intro.mdx b/snippets/subscribe-sync-streams-intro.mdx index a5d6ab140..810e2b47f 100644 --- a/snippets/subscribe-sync-streams-intro.mdx +++ b/snippets/subscribe-sync-streams-intro.mdx @@ -1 +1 @@ -Streams defined with `auto_subscribe: true` start syncing as soon as the client connects. For all other streams, your app must subscribe before their data downloads. The basic pattern is: subscribe to a stream, wait for its data to sync, then unsubscribe when the screen no longer needs the data. +Streams defined with `auto_subscribe: true` start syncing as soon as the client connects. For all other streams, your app must subscribe before their data downloads. The basic pattern is: subscribe to a stream, wait for its data to sync, then unsubscribe when the data is no longer needed. diff --git a/snippets/swift/subscribe-sync-stream.mdx b/snippets/swift/subscribe-sync-stream.mdx index 2de1a6abc..ff90163c9 100644 --- a/snippets/swift/subscribe-sync-stream.mdx +++ b/snippets/swift/subscribe-sync-stream.mdx @@ -6,8 +6,8 @@ let sub = try await db.syncStream(name: "list_todos", params: ["list_id": .strin try await sub.waitForFirstSync() // The stream's rows are now in the local SQLite database. -// TODO: Read the todos for this list with a local query and render them. +// TODO: Read the todos for this list with a local query. -// When the screen no longer needs the data +// When the data is no longer needed try await sub.unsubscribe() ``` From 0faa1b906c435574543fe980c4e5d3348ec85074 Mon Sep 17 00:00:00 2001 From: Benita Volkmann Date: Wed, 9 Sep 2026 16:59:01 +0200 Subject: [PATCH 7/7] Run writing and style standards over the SDk reference pages --- .../config/vocabularies/PowerSync/accept.txt | 4 + client-sdks/reference/capacitor.mdx | 86 +++++++------- client-sdks/reference/dotnet.mdx | 55 +++++---- client-sdks/reference/flutter.mdx | 87 +++++++------- client-sdks/reference/javascript-web.mdx | 102 ++++++++-------- client-sdks/reference/kotlin.mdx | 110 +++++++++--------- client-sdks/reference/node.mdx | 57 ++++----- .../reference/react-native-and-expo.mdx | 91 ++++++++------- client-sdks/reference/rust.mdx | 74 ++++++------ client-sdks/reference/swift.mdx | 65 +++++------ client-sdks/reference/tauri.mdx | 66 +++++------ snippets/generate-schema-automatically.mdx | 6 +- snippets/local-only-escape.mdx | 4 +- snippets/sdk-client-side-schema.mdx | 4 +- snippets/sdk-features.mdx | 2 +- snippets/subscribe-sync-streams-outro.mdx | 2 +- 16 files changed, 399 insertions(+), 416 deletions(-) diff --git a/.github/vale/config/vocabularies/PowerSync/accept.txt b/.github/vale/config/vocabularies/PowerSync/accept.txt index 05dff38f5..024557270 100644 --- a/.github/vale/config/vocabularies/PowerSync/accept.txt +++ b/.github/vale/config/vocabularies/PowerSync/accept.txt @@ -324,3 +324,7 @@ Zod # Package names drift_sqlite_async +PWAs +XCFramework +growable +ps_crud diff --git a/client-sdks/reference/capacitor.mdx b/client-sdks/reference/capacitor.mdx index 46ebb7318..3888fd2ef 100644 --- a/client-sdks/reference/capacitor.mdx +++ b/client-sdks/reference/capacitor.mdx @@ -9,6 +9,7 @@ import CapacitorInstallation from '/snippets/capacitor/installation.mdx'; import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -48,13 +49,13 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill The PowerSync Capacitor SDK is built on top of the [PowerSync Web SDK](/client-sdks/reference/javascript-web). It shares the same API and usage patterns as the Web SDK. The main differences are: - - Uses Capacitor-specific SQLite implementation (`@capacitor-community/sqlite`) for native Android and iOS platforms - - Certain features are not supported on native Android and iOS platforms, see [limitations](#limitations) below for details - - All code examples from the Web SDK apply to Capacitor — use `@powersync/web` for imports instead of `@powersync/capacitor`. See the [JavaScript Web SDK reference](/client-sdks/reference/javascript-web) for ORM support, SPA framework integration, and developer notes. + - It uses the Capacitor-specific SQLite implementation (`@capacitor-community/sqlite`) on native Android and iOS. + - Some features are not supported on native Android and iOS. See [Limitations](#limitations). + + All code examples from the Web SDK apply to Capacitor. Import general components such as `Schema` and `Table` from `@powersync/web`, and `PowerSyncDatabase` from `@powersync/capacitor`. See the [JavaScript Web SDK reference](/client-sdks/reference/javascript-web) for ORM support, SPA framework integration, and developer notes. -### SDK Features +## SDK Features @@ -64,22 +65,20 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** - **Note on imports**: While you install `@powersync/capacitor`, the Capacitor SDK extends the Web SDK so you import general components from `@powersync/web` (installed as a peer dependency). See the [JavaScript Web SDK schema definition section](/client-sdks/reference/javascript-web#1-define-the-client-side-schema) for more advanced examples. + **Imports:** You install `@powersync/capacitor`, but the Capacitor SDK extends the Web SDK, so you import general components from `@powersync/web` (installed as a peer dependency). See the [JavaScript Web SDK schema definition section](/client-sdks/reference/javascript-web#1-define-the-client-side-schema) for more advanced examples. ```js @@ -119,17 +118,17 @@ export type ListRecord = Database['lists']; ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** - The Capacitor PowerSyncDatabase automatically detects the platform and uses the appropriate database drivers: + The Capacitor `PowerSyncDatabase` detects the platform and uses the matching database driver: - **Android and iOS**: Uses [Capacitor Community SQLite](https://github.com/capacitor-community/sqlite) for native database access - **Web**: Falls back to the PowerSync Web SDK @@ -156,7 +155,7 @@ export const db = new PowerSyncDatabase({ }); ``` -When using custom database factories, be sure to specify the `CapacitorSQLiteOpenFactory` for Capacitor platforms: +When you use custom database factories, specify `CapacitorSQLiteOpenFactory` for Capacitor platforms: ```js import { PowerSyncDatabase } from '@powersync/capacitor'; @@ -171,13 +170,13 @@ const db = new PowerSyncDatabase({ }); ``` -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. +After you instantiate the PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. ```js export const setupPowerSync = async () => { - // Uses the backend connector that will be created in the next section + // Uses the backend connector that you create in the next step const connector = new Connector(); db.connect(connector); }; @@ -185,17 +184,17 @@ export const setupPowerSync = async () => { ### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** See the [JavaScript Web SDK backend integration section](/client-sdks/reference/javascript-web#3-integrate-with-your-backend) for connector examples with Supabase and Firebase authentication, and handling `uploadData` with batch operations. @@ -232,7 +231,7 @@ export class Connector { -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. @@ -242,10 +241,10 @@ Once the PowerSync database is connected and your streams have synced, the data The most commonly used CRUD functions to interact with your SQLite data are: -- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (SELECT) a single row from a table. -- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (SELECT) a set of rows from a table. -- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time source tables are modified. -- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (INSERT/UPDATE/DELETE) query. +- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (`SELECT`) a single row from a table. +- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -264,7 +263,7 @@ export const findList = async (id) => { The [getAll](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#getall) method returns a set of rows from a table. ```js -// Get all list IDs +// Get all lists export const getLists = async () => { const results = await db.getAll('SELECT * FROM lists'); return results; @@ -284,26 +283,23 @@ The [watch](https://powersync-ja.github.io/powersync-js/common/interfaces/Common -For advanced watch query features like incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). +For advanced watch query features such as incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). ### Mutations (PowerSync.execute, PowerSync.writeTransaction) The [execute](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#execute) method can be used for executing single SQLite write statements. ```js -// Delete a list item by ID +// Delete a list by ID export const deleteList = async (id) => { - const result = await db.execute('DELETE FROM lists WHERE id = ?', [id]); - return TodoList.fromRow(results); -} + await db.execute('DELETE FROM lists WHERE id = ?', [id]); +}; -// OR: using a transaction -const deleteList = async (id) => { +// OR: delete the list and its todos in one transaction +export const deleteListWithTodos = async (id) => { await db.writeTransaction(async (tx) => { - // Delete associated todos - await tx.execute(`DELETE FROM ${TODOS_TABLE} WHERE list_id = ?`, [id]); - // Delete list record - await tx.execute(`DELETE FROM ${LISTS_TABLE} WHERE id = ?`, [id]); + await tx.execute('DELETE FROM todos WHERE list_id = ?', [id]); + await tx.execute('DELETE FROM lists WHERE id = ?', [id]); }); }; ``` @@ -327,8 +323,8 @@ const logger = createConsoleLogger({ minLevel: LogLevels.trace }); - Encryption for native mobile platforms is not yet supported. - Multiple tab support is not available for native Android and iOS targets. -- `PowerSyncDatabase.executeRaw` does not support results where multiple columns would have the same name in SQLite -- `PowerSyncDatabase.execute` has limited support on Android. The SQLCipher Android driver exposes queries and executions as separate APIs, so there is no single method that handles both. While PowerSyncDatabase.execute accepts both, on Android we treat a statement as a query only when the SQL starts with select (case-insensitive). +- `PowerSyncDatabase.executeRaw` does not support results where multiple columns have the same name in SQLite. +- `PowerSyncDatabase.execute` has limited support on Android. The SQLCipher Android driver exposes queries and executions as separate APIs, so there is no single method that handles both. On Android, the SDK treats a statement as a query only when the SQL starts with `select` (case-insensitive). ## Additional Usage Examples @@ -348,7 +344,7 @@ See [Supported Platforms -> Capacitor SDK](/resources/supported-platforms#capaci ## Upgrading the SDK -Run the below command in your project folder: +Run the following command in your project folder: diff --git a/client-sdks/reference/dotnet.mdx b/client-sdks/reference/dotnet.mdx index 272e04052..8cf1d1047 100644 --- a/client-sdks/reference/dotnet.mdx +++ b/client-sdks/reference/dotnet.mdx @@ -8,6 +8,7 @@ import SdkFeatures from '/snippets/sdk-features.mdx'; import DotNetInstallation from '/snippets/dotnet/installation.mdx'; import DotNetWatch from '/snippets/dotnet/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -40,7 +41,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill - This SDK is currently in a [**beta** release](/resources/feature-status). It is production-ready for tested use cases. APIs are stable and breaking changes will be communicated clearly. + This SDK is currently in a [**beta** release](/resources/feature-status). It is production-ready for tested use cases. APIs are stable, and we communicate breaking changes clearly. ## Supported Frameworks and Targets @@ -49,15 +50,15 @@ The PowerSync .NET SDK supports: * **.NET Versions**: 6, 8, and 9 * **.NET Standard**: 2.0 (for compatibility with older libraries and frameworks) -* **.NET Framework**: Version 4.8 (requires additional configuration — see the package [README](https://github.com/powersync-ja/powersync-dotnet/tree/main?tab=readme-ov-file)) +* **.NET Framework**: Version 4.8, which requires additional configuration (see the package [README](https://github.com/powersync-ja/powersync-dotnet/tree/main?tab=readme-ov-file)) * **MAUI**: Cross-platform support for Android, iOS, Mac Catalyst, and Windows (targeting `net8.0` and `net9.0` mobile frameworks) * **WPF**: Windows desktop applications * **Console/CLI**: Windows (x64, ARM), macOS (x64, ARM), and Linux (x64, ARM) -**Current Limitations**: +**Current limitations:** * Blazor (web) platforms are not yet supported. -For more details, please refer to the package [README](https://github.com/powersync-ja/powersync-dotnet/tree/main?tab=readme-ov-file). +For more details, see the package [README](https://github.com/powersync-ja/powersync-dotnet/tree/main?tab=readme-ov-file). ## SDK Features @@ -67,25 +68,23 @@ For more details, please refer to the package [README](https://github.com/powers -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - You can use [this example](https://github.com/powersync-ja/powersync-dotnet/blob/main/demos/CommandLine/AppSchema.cs) as a reference when defining your schema. -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). #### Schema Definition Syntax There are two supported syntaxes for defining the schema: -**Attribute-based (recommended)** — Annotate a C# class with [`[Table]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.TableAttribute.html), [`[Column]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.ColumnAttribute.html), and [`[Index]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.IndexAttribute.html) attributes. The same class can then be used directly as the result type in queries, so you define your data structure once: +**Attribute-based (recommended):** Annotate a C# class with [`[Table]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.TableAttribute.html), [`[Column]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.ColumnAttribute.html), and [`[Index]`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.DB.Schema.Attributes.IndexAttribute.html) attributes. The same class can then be used directly as the result type in queries, so you define your data structure once: ```cs using PowerSync.Common.DB.Schema; @@ -149,9 +148,9 @@ var todos = await db.GetAll("SELECT * FROM todos"); ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** The initialization syntax differs slightly between the Common and MAUI SDKs: @@ -191,7 +190,7 @@ The initialization syntax differs slightly between the Common and MAUI SDKs: DbFilename = dbPath }); - var Db = new PowerSyncDatabase(new PowerSyncDatabaseOptions() + var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions() { Database = factory, // Supply a factory Schema = AppSchema.PowerSyncSchema, @@ -206,17 +205,17 @@ The initialization syntax differs slightly between the Common and MAUI SDKs: ### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [IPowerSyncBackendConnector.FetchCredentials](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.Connection.IPowerSyncBackendConnector.FetchCredentials.html) - This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [IPowerSyncBackendConnector.UploadData](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.Connection.IPowerSyncBackendConnector.UploadData.html) - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [IPowerSyncBackendConnector.FetchCredentials](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.Connection.IPowerSyncBackendConnector.FetchCredentials.html) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [IPowerSyncBackendConnector.UploadData](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.Connection.IPowerSyncBackendConnector.UploadData.html) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```cs using System; @@ -249,7 +248,7 @@ public class MyConnector : IPowerSyncBackendConnector UserId = "user-123"; // Configure your service endpoints - _backendUrl = "https://your-backend-api.example.com"; + _backendUrl = "[Your backend API URL]"; _powerSyncUrl = "https://your-powersync-instance.powersync.journeyapps.com"; } @@ -346,16 +345,16 @@ await db.WaitForFirstSync(); // Optional, to wait for a complete snapshot of dat -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -- [`PowerSyncDatabase.Get`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Get.html) - get (SELECT) a single row from a table. -- [`PowerSyncDatabase.GetAll`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.GetAll.html) - get (SELECT) a set of rows from a table. -- [`PowerSyncDatabase.Watch`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Watch.html) - execute a read query every time source tables are modified. -- [`PowerSyncDatabase.Execute`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Execute.html) - execute a write (INSERT/UPDATE/DELETE) query. +- [`PowerSyncDatabase.Get`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Get.html) - get (`SELECT`) a single row from a table. +- [`PowerSyncDatabase.GetAll`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.GetAll.html) - get (`SELECT`) a set of rows from a table. +- [`PowerSyncDatabase.Watch`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Watch.html) - execute a read query every time a dependent table changes. +- [`PowerSyncDatabase.Execute`](https://powersync-ja.github.io/powersync-dotnet/api/PowerSync.Common.Client.PowerSyncDatabase.Execute.html) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -392,14 +391,14 @@ The `Execute` method can be used for executing single SQLite write statements. ```cs // And db.Execute for inserts, updates and deletes: await db.Execute( - "insert into lists (id, name, owner_id, created_at) values (uuid(), 'New User', ?, datetime())", + "INSERT INTO lists (id, name, owner_id, created_at) VALUES (uuid(), 'New list', ?, datetime())", [connector.UserId] ); ``` ## Configure Logging -Enable logging to help you debug your app. By default, the SDK uses a no-op logger that doesn't output any logs. To enable logging, you can configure a custom logger using .NET's `ILogger` interface: +By default, the SDK uses a no-op logger that outputs nothing. To enable logging, configure a logger with .NET's `ILogger` interface: ```cs using Microsoft.Extensions.Logging; @@ -436,7 +435,7 @@ See [Supported Platforms -> .NET SDK](/resources/supported-platforms#net). ## Upgrading the SDK -To upgrade to the latest version of the PowerSync package, run the below command in your project folder: +To upgrade the PowerSync package, run the following command in your project folder: diff --git a/client-sdks/reference/flutter.mdx b/client-sdks/reference/flutter.mdx index 0f3b1e35f..c182960aa 100644 --- a/client-sdks/reference/flutter.mdx +++ b/client-sdks/reference/flutter.mdx @@ -8,6 +8,7 @@ import SdkFeatures from '/snippets/sdk-features.mdx'; import FlutterInstallation from '/snippets/flutter/installation.mdx'; import FlutterWatch from '/snippets/flutter/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -35,14 +36,11 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -### Quickstart +## Quickstart -Get started quickly by using the self-hosted **Flutter** + **Supabase** template +To start from a template, use the self-hosted Flutter and Supabase template: [flutter-powersync-supabase](https://github.com/powersync-community/flutter-powersync-supabase). -📂 GitHub Repo -[https://github.com/powersync-community/flutter-powersync-supabase](https://github.com/powersync-community/flutter-powersync-supabase) - -### SDK Features +## SDK Features @@ -56,10 +54,10 @@ Get started quickly by using the self-hosted **Flutter** + **Supabase** template ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). -For this reference document, we assume that you have created a Flutter project and have the following directory structure: +This reference assumes a Flutter project with the following directory structure: ```plaintext lib/ @@ -76,15 +74,15 @@ lib/ ``` -### 1\. Define the Client-Side Schema +### 1. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). + -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** ```dart lib/models/schema.dart import 'package:powersync/powersync.dart'; @@ -111,16 +109,16 @@ const schema = Schema(([ ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. -### 2\. Instantiate the PowerSync Database +### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -To instantiate `PowerSyncDatabase`, inject the Schema you defined in the previous step and a file path — it's important to only instantiate one instance of `PowerSyncDatabase` per file. +To instantiate `PowerSyncDatabase`, pass the schema you defined in the previous step and a file path. Create only one `PowerSyncDatabase` instance per file. -**Example**: +**Example:** ```dart lib/powersync/powersync.dart import 'package:path/path.dart'; @@ -143,7 +141,7 @@ Future openDatabase() async { } ``` -Once you've instantiated your PowerSync database, call the [connect()](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncDatabase/connect.html) method to sync data with your backend. This method requires the backend connector that will be created in the next step. +After you instantiate the PowerSync database, call the [connect()](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncDatabase/connect.html) method to sync data with your backend. This method requires the backend connector that you create in the next step. @@ -186,19 +184,19 @@ class _DemoAppState extends State { } ``` -### 3\. Integrate with Your Backend +### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [PowerSyncBackendConnector.fetchCredentials](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncBackendConnector/fetchCredentials.html) \- This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [PowerSyncBackendConnector.uploadData](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncBackendConnector/uploadData.html) \- This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [PowerSyncBackendConnector.fetchCredentials](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncBackendConnector/fetchCredentials.html) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [PowerSyncBackendConnector.uploadData](https://pub.dev/documentation/powersync/latest/powersync/PowerSyncBackendConnector/uploadData.html) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```dart lib/powersync/my_backend_connector.dart import 'package:powersync/powersync.dart'; @@ -253,7 +251,7 @@ class MyBackendConnector extends PowerSyncBackendConnector { ``` -### 4\. Subscribe to Sync Streams +### 4. Subscribe to Sync Streams @@ -261,32 +259,32 @@ class MyBackendConnector extends PowerSyncBackendConnector { -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -* [PowerSyncDatabase.get](/client-sdks/reference/flutter#fetching-a-single-item) \- get (SELECT) a single row from a table. -* [PowerSyncDatabase.getAll](/client-sdks/reference/flutter#querying-items-powersync-getall) \- get (SELECT) a set of rows from a table. -* [PowerSyncDatabase.watch](/client-sdks/reference/flutter#watching-queries-powersync-watch) \- execute a read query every time source tables are modified. -* [PowerSyncDatabase.execute](/client-sdks/reference/flutter#mutations-powersync-execute) \- execute a write (INSERT/UPDATE/DELETE) query. +* [PowerSyncDatabase.get](/client-sdks/reference/flutter#fetching-a-single-item) - get (`SELECT`) a single row from a table. +* [PowerSyncDatabase.getAll](/client-sdks/reference/flutter#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +* [PowerSyncDatabase.watch](/client-sdks/reference/flutter#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +* [PowerSyncDatabase.execute](/client-sdks/reference/flutter#mutations-powersync-execute) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. -For the following examples, we will define a `TodoList` model class that represents a List of todos. +The following examples use this `TodoList` model class: ```dart lib/models/todolist.dart -/// This is a simple model class representing a TodoList +/// A model class representing a row in the lists table class TodoList { - final int id; + final String id; final String name; final DateTime createdAt; - final DateTime updatedAt; + final String ownerId; TodoList({ required this.id, required this.name, required this.createdAt, - required this.updatedAt, + required this.ownerId, }); factory TodoList.fromRow(Map row) { @@ -294,7 +292,7 @@ class TodoList { id: row['id'], name: row['name'], createdAt: DateTime.parse(row['created_at']), - updatedAt: DateTime.parse(row['updated_at']), + ownerId: row['owner_id'], ); } } @@ -304,9 +302,10 @@ class TodoList { The [get](https://pub.dev/documentation/powersync/latest/sqlite_async/SqliteConnection/get.html) method executes a read-only (SELECT) query and returns a single result. It throws an exception if no result is found. Use [getOptional](https://pub.dev/documentation/powersync/latest/sqlite_async/SqliteConnection/getOptional.html) to return a single optional result (returns `null` if no result is found). -The following is an example of selecting a list item by ID: +The following example selects a list by ID: + ```dart lib/widgets/lists_widget.dart -import '../main.dart'; +import '../powersync/powersync.dart'; import '../models/todolist.dart'; Future find(id) async { @@ -321,7 +320,7 @@ The [getAll](https://pub.dev/documentation/powersync/latest/sqlite_async/SqliteC ```dart lib/widgets/lists_widget.dart import 'package:powersync/sqlite3.dart'; -import '../main.dart'; +import '../powersync/powersync.dart'; Future> getLists() async { ResultSet results = await db.getAll('SELECT id FROM lists WHERE id IS NOT NULL'); @@ -342,7 +341,7 @@ The [execute](https://pub.dev/documentation/powersync/latest/sqlite_async/Sqlite ```dart lib/widgets/todos_widget.dart {12-15} import 'package:flutter/material.dart'; -import '../main.dart'; +import '../powersync/powersync.dart'; // Example Todos widget class TodosWidget extends StatelessWidget { @@ -410,7 +409,7 @@ Future connect(PowerSyncDatabase db) async { ``` - On the web, PowerSync uses a shared worker for the sync process. As Dart objects cannot be shared between tabs and workers, the worker will use a + On the web, PowerSync uses a shared worker for the sync process. As Dart objects cannot be shared between tabs and workers, the worker uses a random tab as a proxy to send requests. This can slow down the sync process slightly. @@ -434,7 +433,7 @@ See [Supported Platforms -> Dart SDK](/resources/supported-platforms#dart/flutte ## Upgrading the SDK -To upgrade to a newer version of the PowerSync package, run the below command in your project folder: +To upgrade the PowerSync package, run the following command in your project folder: ```bash dart pub upgrade powersync diff --git a/client-sdks/reference/javascript-web.mdx b/client-sdks/reference/javascript-web.mdx index 28043b060..84c5477dd 100644 --- a/client-sdks/reference/javascript-web.mdx +++ b/client-sdks/reference/javascript-web.mdx @@ -9,6 +9,7 @@ import JavaScriptWebInstallation from '/snippets/javascript-web/installation.mdx import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; import JavaScriptSubscribeSyncStream from '/snippets/javascript/subscribe-sync-stream.mdx'; @@ -41,13 +42,13 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -### SDK Features +## SDK Features ## Single-Page Application (SPA) Frameworks -The PowerSync [JavaScript Web SDK](../javascript-web) is compatible with popular Single-Page Application (SPA) frameworks like React, Vue, Angular, and Svelte. Integration packages are provided specifically for the following: +The PowerSync JavaScript Web SDK is compatible with popular Single-Page Application (SPA) frameworks like React, Vue, Angular, and Svelte. Integration packages are provided specifically for the following: @@ -69,7 +70,7 @@ The PowerSync [JavaScript Web SDK](../javascript-web) is compatible with popular * The [`@powersync/react`](/client-sdks/frameworks/react) package is best for most basic use cases, especially when you only need reactive queries with loading and error states. - * For more advanced scenarios, such as query caching and pagination, [TanStack Query](/client-sdks/frameworks/tanstack#tanstack-query) is a powerful solution. The [`@powersync/tanstack-react-query`](/client-sdks/frameworks/tanstack#tanstack-query) package extends the `useQuery` hook from `@powersync/react` and adds functionality from [TanStack Query](https://tanstack.com/query/latest/docs/framework/react/overview), making it a better fit for advanced use cases or performance-optimized apps. + * For more advanced scenarios, such as query caching and pagination, use [TanStack Query](/client-sdks/frameworks/tanstack#tanstack-query). The [`@powersync/tanstack-react-query`](/client-sdks/frameworks/tanstack#tanstack-query) package extends the `useQuery` hook from `@powersync/react` with functionality from [TanStack Query](https://tanstack.com/query/latest/docs/framework/react/overview). * For reactive data management and live query support across multiple frameworks, consider [TanStack DB](/client-sdks/frameworks/tanstack#tanstack-db). PowerSync works with all TanStack DB framework adapters (React, Vue, Solid, Svelte, Angular). @@ -83,19 +84,17 @@ The PowerSync [JavaScript Web SDK](../javascript-web) is compatible with popular ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** ```js // AppSchema.ts @@ -134,14 +133,14 @@ export type ListRecord = Database['lists']; ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** ```js import { PowerSyncDatabase } from '@powersync/web'; @@ -160,13 +159,13 @@ export const db = new PowerSyncDatabase({ }); ``` -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. +After you instantiate the PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. ```js export const setupPowerSync = async () => { - // Uses the backend connector that will be created in the next section + // Uses the backend connector that you create in the next step const connector = new Connector(); db.connect(connector); }; @@ -174,17 +173,17 @@ export const setupPowerSync = async () => { ### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```js import { UpdateType } from '@powersync/web'; @@ -219,16 +218,16 @@ If you use React, the `useQuery` hook accepts a `streams` option and the `useSyn -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (SELECT) a single row from a table. -- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (SELECT) a set of rows from a table. -- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time source tables are modified. -- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (INSERT/UPDATE/DELETE) query. +- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (`SELECT`) a single row from a table. +- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -247,7 +246,7 @@ export const findList = async (id) => { The [getAll](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#getall) method returns a set of rows from a table. ```js -// Get all list IDs +// Get all lists export const getLists = async () => { const results = await db.getAll('SELECT * FROM lists'); return results; @@ -267,26 +266,23 @@ The [watch](https://powersync-ja.github.io/powersync-js/common/interfaces/Common -For advanced watch query features like incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). +For advanced watch query features such as incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). ### Mutations (PowerSync.execute, PowerSync.writeTransaction) The [execute](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#execute) method can be used for executing single SQLite write statements. ```js -// Delete a list item by ID +// Delete a list by ID export const deleteList = async (id) => { - const result = await db.execute('DELETE FROM lists WHERE id = ?', [id]); - return TodoList.fromRow(results); -} + await db.execute('DELETE FROM lists WHERE id = ?', [id]); +}; -// OR: using a transaction -const deleteList = async (id) => { +// OR: delete the list and its todos in one transaction +export const deleteListWithTodos = async (id) => { await db.writeTransaction(async (tx) => { - // Delete associated todos - await tx.execute(`DELETE FROM ${TODOS_TABLE} WHERE list_id = ?`, [id]); - // Delete list record - await tx.execute(`DELETE FROM ${LISTS_TABLE} WHERE id = ?`, [id]); + await tx.execute('DELETE FROM todos WHERE list_id = ?', [id]); + await tx.execute('DELETE FROM lists WHERE id = ?', [id]); }); }; ``` @@ -344,8 +340,7 @@ See [JavaScript ORM Support](/client-sdks/orms/js/overview) for details. allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen > -📂 GitHub Repo -[https://github.com/powersync-community/vite-react-ts-powersync-supabase/](https://github.com/powersync-community/vite-react-ts-powersync-supabase/) +Template repo: [vite-react-ts-powersync-supabase](https://github.com/powersync-community/vite-react-ts-powersync-supabase/) ## Troubleshooting @@ -357,7 +352,7 @@ See [Supported Platforms -> JS/Web SDK](/resources/supported-platforms#javascrip ## Upgrading the SDK -Run the below command in your project folder: +Run the following command in your project folder: @@ -386,8 +381,8 @@ This SDK supports two methods for streaming sync commands: 1. **HTTP Streaming (Default)** - This is the default and recommended connection method. 2. **WebSocket** - - This implementation leverages RSocket based on WebSocket connections. - - Window sizes for flow control and back-pressure are customizable, set `fetchStrategy` to `Buffered` (default) or `Sequential`. + - This implementation uses RSocket over WebSocket connections. + - To customize window sizes for flow control and back-pressure, set `fetchStrategy` to `Buffered` (default) or `Sequential`. - On the web, there is no compelling reason to use WebSockets over HTTP response streams. By default, the `PowerSyncDatabase.connect()` method uses HTTP streaming. You can optionally specify the `connectionMethod` to override this: @@ -406,11 +401,11 @@ This SDK supports multiple Virtual File Systems (VFS), each responsible for stor #### 1. IDBBatchAtomicVFS (Default) -The default VFS for applications needing the broadest browser compatibility. This system utilizes IndexedDB as its underlying storage mechanism. Multiple tabs are fully supported across most modern browsers, and no additional configuration is needed. +The default VFS for applications that need the broadest browser compatibility. It uses IndexedDB for storage. Multiple tabs are fully supported across most modern browsers, and no additional configuration is needed. -#### 2. OPFS-based Alternatives +#### 2. OPFS-Based Alternatives -PowerSync supports three OPFS (Origin Private File System) implementations that generally offer improved performance compared to IndexedDB: +PowerSync supports three OPFS (Origin Private File System) implementations that are generally faster than IndexedDB: **OPFSCoopSyncVFS** @@ -473,8 +468,7 @@ export const db = new PowerSyncDatabase({ #### 3. In-Memory VFS -Since version 1.39.0 of the `@powersync/web` package, you can use an in-memory database with `WASQLiteVFS.InMemoryVfs`. -It runs queries faster than any other single-threaded VFS (both IndexedDB and OPFS, except the write-ahead VFS). +Since version 1.39.0 of the `@powersync/web` package, you can use an in-memory database with `WASQLiteVFS.InMemoryVfs`. It runs queries faster than any other single-threaded VFS (both IndexedDB and OPFS, except the write-ahead VFS). No data is persisted: local writes are lost if they aren't uploaded before the tab is closed, and all data is resynced whenever a tab is opened. This makes it unsuitable for apps that need to work offline, but a good fit for: @@ -488,7 +482,7 @@ local mutations exist and indicate that state to the user. A `beforeunload` even call `preventDefault()` on tab close events, causing browsers to ask for confirmation before closing the tab. -With Chrome and Firefox on Desktop, this VFS will use a shared worker to enable multi-tab support by default, meaning that all +With Chrome and Firefox on desktop, this VFS uses a shared worker to enable multi-tab support by default, meaning that all tabs have access to the same data and will share a sync worker. This behavior can be enabled or disabled on all browsers by passing the [`enableMultiTabs` flag](#available-flags). @@ -519,7 +513,9 @@ export const db = new PowerSyncDatabase({ | InMemoryWriteAheadLogPool | ❌ (isolated per tab)| ❌ (isolated per tab) | ✅ | Highly concurrent, non-persistent workloads; requires cross-origin isolation | -**Note**: There are known issues with OPFS (all variants) when using Safari's incognito mode. + + There are known issues with OPFS (all variants) in Safari's incognito mode. + ### Multi-Threaded In-Memory SQLite Connection Pool @@ -626,7 +622,7 @@ The SDK still tries to share state across tabs using broadcast channels (since v ### Using PowerSyncDatabase Flags -This guide provides an overview of the customizable flags available for the `PowerSyncDatabase` in the JavaScript Web SDK. These flags allow you to enable or disable specific features to suit your application's requirements. +The `PowerSyncDatabase` constructor accepts the following flags. Use them to enable or disable specific features. #### Configuring Options @@ -650,7 +646,7 @@ export const db = new PowerSyncDatabase({ default: `true` (`false` on Android, iOS, and Safari) - Enables support for multiple tabs using shared web workers. When enabled, multiple tabs can interact with the same database and sync data seamlessly. + Enables support for multiple tabs using shared web workers. When enabled, multiple tabs share the same database and sync connection. @@ -714,9 +710,9 @@ export const db = new PowerSyncDatabase({ }); ``` -Logs will include detailed insights into database and sync operations. +Logs include details of database and sync operations. #### Recommendations -1. **Set `enableMultiTabs`** to `true` if your application requires seamless data sharing across multiple tabs. +1. **Set `enableMultiTabs`** to `true` if your application shares data across multiple tabs. 2. **Set `broadcastLogs`** to `true` during development to troubleshoot and monitor database and sync operations. diff --git a/client-sdks/reference/kotlin.mdx b/client-sdks/reference/kotlin.mdx index 871de6839..d9ca2e5ec 100644 --- a/client-sdks/reference/kotlin.mdx +++ b/client-sdks/reference/kotlin.mdx @@ -8,6 +8,7 @@ import SdkFeatures from '/snippets/sdk-features.mdx'; import KotlinInstallation from '/snippets/kotlin/installation.mdx'; import KotlinWatch from '/snippets/kotlin/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -35,7 +36,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -### SDK Features +## SDK Features @@ -46,23 +47,23 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill **Supported platforms** * PowerSync supports Android, JVM and Apple (iOS, macOS, tvOS, watchOS) targets through Kotlin Multiplatform. - * On the JVM, the following platforms are supported: Linux AArch64, Linux X64, MacOS AArch64, MacOS X64, Windows X64. + * On the JVM, the following platforms are supported: Linux AArch64, Linux X64, macOS AArch64, macOS X64, Windows X64. * Web (JS and WebAssembly) targets have experimental support. See [Experimental Web Support](#experimental-web-support). ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). -### 1\. Define the Client-Side Schema +### 1. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). + -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** ```kotlin // AppSchema.kt @@ -77,13 +78,13 @@ val AppSchema: Schema = Schema( Table( name = "todos", columns = listOf( - Column.text('list_id'), - Column.text('created_at'), - Column.text('completed_at'), - Column.text('description'), - Column.integer('completed'), - Column.text('created_by'), - Column.text('completed_by') + Column.text("list_id"), + Column.text("created_at"), + Column.text("completed_at"), + Column.text("description"), + Column.integer("completed"), + Column.text("created_by"), + Column.text("completed_by") ), // Index to allow efficient lookup within a list indexes = listOf( @@ -93,25 +94,25 @@ val AppSchema: Schema = Schema( Table( name = "lists", columns = listOf( - Column.text('created_at'), - Column.text('name'), - Column.text('owner_id') + Column.text("created_at"), + Column.text("name"), + Column.text("owner_id") ) ) ) ) ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. -### 2\. Instantiate the PowerSync Database +### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** -a. Create platform specific `DatabaseDriverFactory` to be used by the `PowerSyncBuilder` to create the SQLite database driver. +a. Create a platform-specific `DatabaseDriverFactory` to be used by the `PowerSyncBuilder` to create the SQLite database driver. ```kotlin // commonMain @@ -130,13 +131,13 @@ b. Build a `PowerSyncDatabase` instance using the `PowerSyncBuilder` and the `Da ```kotlin // commonMain -val database = PowerSyncDatabase({ - factory: driverFactory, // The factory you defined above - schema: AppSchema, // The schema you defined in the previous step - dbFilename: "powersync.db" - // logger: YourLogger // Optionally include your own Logger that must conform to Kermit Logger - // dbDirectory: "path/to/directory" // Optional. Directory path where the database file is located. This parameter is ignored for iOS. -}); +val database = PowerSyncDatabase( + factory = driverFactory, // The factory you defined above + schema = AppSchema, // The schema you defined in the previous step + dbFilename = "powersync.db", + // logger = YourLogger, // Optional. Your own Kermit Logger. + // dbDirectory = "path/to/directory", // Optional. Directory for the database file. Ignored on iOS. +) ``` c. Connect the `PowerSyncDatabase` to sync data with your backend: @@ -146,7 +147,7 @@ c. Connect the `PowerSyncDatabase` to sync data with your backend: ```kotlin // commonMain -// Uses the backend connector that will be created in the next step +// Uses the backend connector that you create in the next step database.connect(MyConnector()) ``` @@ -162,19 +163,19 @@ remember { } ``` -### 3\. Integrate with Your Backend +### 3. Integrate with Your Backend -Create a connector to integrate with your backend. The PowerSync backend connector provides the connection between your application backend and the PowerSync managed database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. `PowerSyncBackendConnector.fetchCredentials` \- This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. `PowerSyncBackendConnector.uploadData` \- This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. `PowerSyncBackendConnector.fetchCredentials` - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. `PowerSyncBackendConnector.uploadData` - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```kotlin // PowerSync.kt @@ -186,11 +187,11 @@ class MyConnector : PowerSyncBackendConnector() { // implement fetchCredentials to obtain the necessary credentials to connect to your backend // See an example implementation in https://github.com/powersync-ja/powersync-kotlin/blob/main/integrations/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt - return { - endpoint: '[Your PowerSync instance URL or self-hosted endpoint]', + return PowerSyncCredentials( + endpoint = "[Your PowerSync instance URL or self-hosted endpoint]", // Use a development token (see Authentication Setup https://docs.powersync.com/configuration/auth/development-tokens) to get up and running quickly - token: 'An authentication token' - } + token = "An authentication token" + ) } override suspend fun uploadData(database: PowerSyncDatabase) { @@ -202,9 +203,9 @@ class MyConnector : PowerSyncBackendConnector() { } ``` -**Note**: If you are using Supabase, you can use [SupabaseConnector.kt](https://github.com/powersync-ja/powersync-kotlin/blob/main/integrations/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt) as a starting point. +If you use Supabase, you can use [SupabaseConnector.kt](https://github.com/powersync-ja/powersync-kotlin/blob/main/integrations/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt) as a starting point. -### 4\. Subscribe to Sync Streams +### 4. Subscribe to Sync Streams @@ -212,16 +213,16 @@ class MyConnector : PowerSyncBackendConnector() { -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -* [PowerSyncDatabase.get](/client-sdks/reference/kotlin#fetching-a-single-item) \- get (SELECT) a single row from a table. -* [PowerSyncDatabase.getAll](/client-sdks/reference/kotlin#querying-items-powersync-getall) \- get (SELECT) a set of rows from a table. -* [PowerSyncDatabase.watch](/client-sdks/reference/kotlin#watching-queries-powersync-watch) \- execute a read query every time source tables are modified. -* [PowerSyncDatabase.execute](/client-sdks/reference/kotlin#mutations-powersync-execute) \- execute a write (INSERT/UPDATE/DELETE) query. +* [PowerSyncDatabase.get](/client-sdks/reference/kotlin#fetching-a-single-item) - get (`SELECT`) a single row from a table. +* [PowerSyncDatabase.getAll](/client-sdks/reference/kotlin#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +* [PowerSyncDatabase.watch](/client-sdks/reference/kotlin#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +* [PowerSyncDatabase.execute](/client-sdks/reference/kotlin#mutations-powersync-execute) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -302,7 +303,7 @@ suspend fun deleteCustomer(id: String? = null) { ## Configure Logging -You can include your own Logger that must conform to the [Kermit Logger](https://kermit.touchlab.co/docs/) as shown here. +You can supply your own logger. It must conform to the [Kermit Logger](https://kermit.touchlab.co/docs/): ```kotlin PowerSyncDatabase( @@ -311,7 +312,7 @@ PowerSyncDatabase( ) ``` -If you don't supply a Logger then a default Kermit Logger is created with settings to only show `Warnings` in release and `Verbose` in debug as follows: +If you do not supply a logger, the SDK creates a default Kermit Logger. It shows `Warn` and above in release builds and `Verbose` in debug builds: ```kotlin val defaultLogger: Logger = Logger @@ -326,7 +327,7 @@ if(BuildConfig.isDebug) { return defaultLogger ``` -You are able to use the Logger anywhere in your code as follows to debug: +You can use the logger anywhere in your code: ```kotlin import co.touchlab.kermit.Logger @@ -386,8 +387,7 @@ For more usage examples including accessing connection status, monitoring sync p ## ORM / SQL Library Support -The PowerSync SDK for Kotlin can be used with the SQLDelight and Room libraries, making it easier to define and -run SQL queries. +You can use the Kotlin SDK with the SQLDelight and Room libraries to define and run SQL queries. For details, see the [SQL Library Support](/client-sdks/orms/kotlin/overview) page. ## Experimental Web Support @@ -397,7 +397,7 @@ Version 1.14.1 of the SDK adds initial support for web targets (JS and WebAssemb Web support is experimental and incomplete. We are sharing it for early testing and prototyping purposes, and it is not ready for production use. The main limitation is that multi-tab support is not functional in this version: tabs don't coordinate sync connections or share update notifications, so use the database from a single tab only. -If you try web support, please test it thoroughly and report any issues you run into on [GitHub](https://github.com/powersync-ja/powersync-kotlin/issues). Follow the [tracking issue](https://github.com/powersync-ja/powersync-kotlin/issues/362) for progress on stabilizing web support. +If you try web support, test it thoroughly and report any issues on [GitHub](https://github.com/powersync-ja/powersync-kotlin/issues). Follow the [tracking issue](https://github.com/powersync-ja/powersync-kotlin/issues/362) for progress on stabilizing web support. For a working example, see the web target of the [Supabase To-Do List demo](https://github.com/powersync-ja/powersync-kotlin/tree/main/demos/supabase-todolist). diff --git a/client-sdks/reference/node.mdx b/client-sdks/reference/node.mdx index dcb25c879..13e78c513 100644 --- a/client-sdks/reference/node.mdx +++ b/client-sdks/reference/node.mdx @@ -1,5 +1,5 @@ --- -title: "Node.js client SDK" +title: "Node.js Client SDK" description: "Use PowerSync in Node.js apps." sidebarTitle: "SDK Reference" --- @@ -9,6 +9,7 @@ import NodeInstallation from '/snippets/node/installation.mdx'; import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -47,7 +48,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -### SDK Features +## SDK Features @@ -55,27 +56,26 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - You can use [this example](https://github.com/powersync-ja/powersync-js/blob/e5a57a539150f4bc174e109d3898b6e533de272f/demos/example-node/src/powersync.ts#L47-L77) as a reference when defining your schema. -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +In the Dashboard, select JavaScript and replace the suggested import with `@powersync/node`. + +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). - Select JavaScript and replace the suggested import with `@powersync/node`. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** ```js import { PowerSyncDatabase } from '@powersync/node'; @@ -96,27 +96,22 @@ export const db = new PowerSyncDatabase({ ### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```js import { UpdateType } from '@powersync/node'; -export class Connector implements PowerSyncBackendConnector { - constructor() { - // set up a connection to your server for uploads - this.serverConnectionClient = TODO; - } - +export class Connector { async fetchCredentials() { // Implement fetchCredentials to obtain a JWT from your authentication service. // See https://docs.powersync.com/configuration/auth/overview @@ -155,8 +150,7 @@ await db.waitForFirstSync(); // Optional, to wait for a complete snapshot of dat ## Usage -Once the database is connected and your streams have synced, the data is in the local SQLite database. The API to run queries and updates is identical to our -[JavaScript/Web SDK](/client-sdks/reference/javascript-web#using-powersync-crud-functions): +Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The API to run queries and updates is identical to the [JavaScript Web SDK](/client-sdks/reference/javascript-web#using-powersync-crud-functions): ```js // Use db.get() to fetch a single row: @@ -167,7 +161,7 @@ console.log(await db.getAll('SELECT * FROM lists;')); // And db.execute for inserts, updates and deletes: await db.execute( - "INSERT INTO lists (id, created_at, name, owner_id) VALUEs (uuid(), datetime('now'), ?, uuid());", + "INSERT INTO lists (id, created_at, name, owner_id) VALUES (uuid(), datetime('now'), ?, uuid());", ['My new list'] ); ``` @@ -189,10 +183,10 @@ The `db.watch()` method executes a read query whenever a change to a dependent t -For advanced watch query features like incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). +For advanced watch query features such as incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). -PowerSync runs queries asynchronously on a background pool of workers and automatically configures WAL to allow a writer and multiple readers to operate in parallel. +PowerSync runs queries asynchronously on a background pool of workers. It configures SQLite write-ahead logging (WAL) so that one writer and multiple readers can operate in parallel. ## Configure Logging @@ -226,7 +220,7 @@ See [Supported Platforms -> Node.js SDK](/resources/supported-platforms#node-js) ## Upgrading the SDK -Run the below command in your project folder: +Run the following command in your project folder: @@ -318,8 +312,8 @@ toolchain. ### `node:sqlite` Recent versions of Node.js contain an [experimental SQLite API](https://nodejs.org/api/sqlite.html). -Using the builtin SQLite API can reduce code size and external native dependencies. To enable it, -remove your dependency on `better-sqlite3` and configure PowerSync to use the builtin APIs: +Using the built-in SQLite API can reduce code size and external native dependencies. To enable it, +remove your dependency on `better-sqlite3` and configure PowerSync to use the built-in API: ```JavaScript const database = new PowerSyncDatabase({ @@ -334,6 +328,5 @@ const database = new PowerSyncDatabase({ ``` -There are stability issues when using PowerSync with this API, and it's not recommended outside of -testing purposes at the moment. +PowerSync has stability issues with this API. Use it for testing only. diff --git a/client-sdks/reference/react-native-and-expo.mdx b/client-sdks/reference/react-native-and-expo.mdx index 1f4f60a52..b8472ac25 100644 --- a/client-sdks/reference/react-native-and-expo.mdx +++ b/client-sdks/reference/react-native-and-expo.mdx @@ -9,6 +9,7 @@ import ReactNativeInstallation from '/snippets/react-native/installation.mdx'; import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -27,7 +28,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill Refer to packages/react-native in the powersync-js repo on GitHub -Full API reference for the PowerSync SDK +Full API reference for the SDK Gallery of example projects/demo apps built with React Native and PowerSync. @@ -37,13 +38,13 @@ Full API reference for the PowerSync SDK -### SDK Features +## SDK Features ## Using Hooks -A separate `powersync-react` package is available containing React hooks for PowerSync. See its README for example code. +The `@powersync/react` package provides React hooks for PowerSync. See [React Hooks](/client-sdks/frameworks/react) for examples. -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: - - - **Note**: No need to declare a primary key `id` column - as PowerSync will automatically create this. - +**Example:** ```typescript powersync/AppSchema.ts import { column, Schema, Table } from '@powersync/react-native'; @@ -110,11 +107,15 @@ export type TodoRecord = Database['todos']; export type ListRecord = Database['lists']; ``` -### 2\. Instantiate the PowerSync Database + + You do not need to declare an `id` column. PowerSync creates it automatically. + -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +### 2. Instantiate the PowerSync Database -**Example**: +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. + +**Example:** ```typescript powersync/system.ts import { PowerSyncDatabase } from '@powersync/react-native'; @@ -132,7 +133,7 @@ export const powersync = new PowerSyncDatabase({ }); ``` -Once you've instantiated your PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. +After you instantiate the PowerSync database, call the [connect()](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#connect) method to sync data with your backend. @@ -140,25 +141,25 @@ Once you've instantiated your PowerSync database, call the [connect()](https://p import { Connector } from './Connector'; export const setupPowerSync = async () => { - // Uses the backend connector that will be created in the next section + // Uses the backend connector that you create in the next step const connector = new Connector(); powersync.connect(connector); }; ``` -### 3\. Integrate with Your Backend +### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-slide managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) \- This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) \- This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. [PowerSyncBackendConnector.fetchCredentials](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L16) - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. [PowerSyncBackendConnector.uploadData](https://github.com/powersync-ja/powersync-js/blob/ed5bb49b5a1dc579050304fab847feb8d09b45c7/packages/common/src/client/connection/PowerSyncBackendConnector.ts#L24) - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```typescript powersync/Connector.ts import { type PowerSyncBackendConnector, type CommonPowerSyncDatabase, UpdateType } from "@powersync/react-native" @@ -219,7 +220,7 @@ export class Connector implements PowerSyncBackendConnector { } ``` -### 4\. Subscribe to Sync Streams +### 4. Subscribe to Sync Streams @@ -229,16 +230,16 @@ If you use React, the `useQuery` hook accepts a `streams` option and the `useSyn -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -* [PowerSyncDatabase.get](#fetching-a-single-item) \- get (`SELECT`) a single row from a table. -* [PowerSyncDatabase.getAll](#querying-items-powersync-getall) \- get (`SELECT`) a set of rows from a table. -* [PowerSyncDatabase.watch](#watching-queries-powersync-watch) \- execute a read query every time source tables are modified. -* [PowerSyncDatabase.execute](#mutations-powersync-execute) \- execute a write (`INSERT`/`UPDATE`/`DELETE`) query. +* [PowerSyncDatabase.get](#fetching-a-single-item) - get (`SELECT`) a single row from a table. +* [PowerSyncDatabase.getAll](#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +* [PowerSyncDatabase.watch](#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +* [PowerSyncDatabase.execute](#mutations-powersync-execute) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -299,7 +300,7 @@ The [watch](https://powersync-ja.github.io/powersync-js/common/interfaces/Common -For advanced watch query features like incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). +For advanced watch query features such as incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). ### Mutations (`PowerSync.execute`) @@ -326,7 +327,7 @@ export const ListsWidget = () => { await powersync.execute(`DELETE FROM lists WHERE id = ?`, [item.id]) // Watched queries should automatically reload after mutation } catch (ex) { - Alert('Error', ex.message) + Alert.alert('Error', ex.message) } }} /> @@ -386,7 +387,7 @@ See [Supported Platforms -> React Native SDK](/resources/supported-platforms#rea ## Upgrading the SDK -Run the below command in your project folder: +Run the following command in your project folder: @@ -415,9 +416,9 @@ This SDK supports two methods for streaming sync commands: 1. **HTTP Streaming (Default)** - This is the default streaming method for Expo apps. 2. **WebSocket (Fallback)** - - The implementation leverages RSocket for handling reactive socket streams. + - This implementation uses RSocket for reactive socket streams. - This is necessary on React Native without Expo, as `fetch()` in React Native does not support streaming responses. - - Window sizes for flow control and back-pressure are customizable, set `fetchStrategy` to `Buffered` (default) or `Sequential`. + - To customize window sizes for flow control and back-pressure, set `fetchStrategy` to `Buffered` (default) or `Sequential`. By default, the `PowerSyncDatabase.connect()` method uses HTTP on Expo apps (with `expo/fetch` as an HTTP client) and WebSockets for plain React Native apps. You can optionally specify the `connectionMethod` to override this: @@ -435,13 +436,13 @@ powerSync.connect(connector, { connectionMethod: SyncStreamConnectionMethod.WEB_ ### Android: Flipper Network Plugin for HTTP Streams -If you are connecting to PowerSync using HTTP streams (the default), you require additional configuration on Android. React Native does not support streams out of the box, so we use the [polyfills mentioned](/client-sdks/reference/react-native-and-expo#installation). There is currently an open [issue](https://github.com/facebook/flipper/issues/2495) where the Flipper network plugin does not allow Stream events to fire. This plugin needs to be [disabled](https://stackoverflow.com/questions/69235694/react-native-cant-connect-to-sse-in-android/69235695#69235695) in order for HTTP streams to work. +If you connect to PowerSync with HTTP streams (the default), Android requires additional configuration. React Native does not support streams natively, so the SDK uses the [polyfills](/client-sdks/reference/react-native-and-expo#installation) from the installation steps. An open Flipper [issue](https://github.com/facebook/flipper/issues/2495) prevents the Flipper network plugin from firing stream events. [Disable the plugin](https://stackoverflow.com/questions/69235694/react-native-cant-connect-to-sse-in-android/69235695#69235695) so that HTTP streams work. **If you are using Java (Expo < 50):** -Uncomment the following from `android/app/src/debug/java/com//ReactNativeFlipper.java` +Uncomment the following in `android/app/src/debug/java/com//ReactNativeFlipper.java`: -```js +```java // NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); // NetworkingModule.setCustomClientBuilder( // new NetworkingModule.CustomClientBuilder() { @@ -453,18 +454,18 @@ Uncomment the following from `android/app/src/debug/java/com//React // client.addPlugin(networkFlipperPlugin); ``` -Disable the dev client network inspector `android/gradle.properties` +Disable the dev client network inspector in `android/gradle.properties`: -```bash -# Enable network inspector +```properties +# Disable the network inspector EX_DEV_CLIENT_NETWORK_INSPECTOR=false ``` **If you are using Kotlin (Expo > 50):** -Comment out the following from `onCreate` in `android/app/src/main/java/com//example/MainApplication.kt` +Comment out the following in `onCreate` in `android/app/src/main/java/com//example/MainApplication.kt`: -```js +```kotlin // if (BuildConfig.DEBUG) { // ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) // } @@ -472,4 +473,4 @@ Comment out the following from `onCreate` in `android/app/src/main/java/com/ -### SDK Features +## SDK Features @@ -49,17 +50,17 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). -### 1\. Define the Client-Side Schema +### 1. Define the Client-Side Schema -The first step is to define the client-side schema, which refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The client-side schema is typically mainly derived from your backend source database schema and your [Sync Streams](/sync/streams/overview), but can also include other tables such as local-only tables. Note that schema migrations are not required on the SQLite database due to the schemaless nature of the [PowerSync protocol](/architecture/powersync-protocol): schemaless data is synced to the client-side SQLite database, and the client-side schema is then applied to that data using _SQLite views_ to allow for structured querying of the data. The schema is applied when the local PowerSync database is constructed (as we'll show in the next step). + -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** ```Rust src/schema.rs use powersync::schema::{Column, Schema, Table}; @@ -96,16 +97,16 @@ pub fn app_schema() -> Schema { } ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. -### 2\. Instantiate the PowerSync Database +### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. #### Process Setup -PowerSync is based on SQLite, and statically links the [PowerSync SQLite core extension](https://github.com/powersync-ja/powersync-sqlite-core), which needs to be enabled for the process before the SDK can be used. The SDK offers a utility to register the extension, and we recommend calling it early in `main()`: +The SDK statically links the [PowerSync SQLite core extension](https://github.com/powersync-ja/powersync-sqlite-core). You must register the extension for the process before you use the SDK. We recommend calling the registration utility early in `main()`: ```Rust lib/main.rs use powersync::env::PowerSyncEnvironment; @@ -122,7 +123,7 @@ fn main() { #### Database Setup -For maximum flexibility, the PowerSync Rust SDK can be configured with different asynchronous runtimes and HTTP clients used to connect to the PowerSync Service. +You can configure the Rust SDK with different asynchronous runtimes and HTTP clients to connect to the PowerSync Service. These dependencies can be configured through the [`PowerSyncEnvironment`](https://docs.rs/powersync/latest/powersync/env/struct.PowerSyncEnvironment.html) struct, which wraps: @@ -166,8 +167,8 @@ fn open_pool() -> Result { Next, create a database and start asynchronous tasks used by the sync client when connecting. To be compatible with different executors, the SDK uses a model based on long-lived actors instead of -spawning tasks dynamically. All asynchronous processes are exposed through `PowerSyncDatabase::async_tasks()`, -these tasks must be spawned before connecting. +spawning tasks dynamically. All asynchronous processes are exposed through `PowerSyncDatabase::async_tasks()`. +Spawn these tasks before connecting. @@ -231,8 +232,8 @@ PowerSync is executor-agnostic and supports all async Rust runtimes. You need to 2. A way to spawn futures as a task that is polled independently. PowerSync uses the [`Timer`](https://docs.rs/powersync/latest/powersync/env/trait.Timer.html) -trait for timers, it can be installed by creating a `PowerSyncEnvironment` with `PowerSyncEnvironment::custom` -and passing your custom timer implementation. +trait for timers. Install your timer by creating a `PowerSyncEnvironment` with `PowerSyncEnvironment::custom` +and passing your implementation. Spawning tasks is only necessary once after opening the database. All tasks necessary for the sync client are exposed through `PowerSyncDatabase::async_tasks`. You can spawn these by providing @@ -251,19 +252,19 @@ db.connect(SyncOptions::new(MyBackendConnector { -### 3\. Integrate with Your Backend +### 3. Integrate with Your Backend -Create a connector to integrate with your backend. The PowerSync backend connector provides the connection between your application backend and the PowerSync managed database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. `fetch_credentials` \- This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. `upload_data` \- This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. `fetch_credentials` - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. `upload_data` - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```Rust struct MyBackendConnector { @@ -299,7 +300,7 @@ impl BackendConnector for MyBackendConnector { } ``` -### 4\. Subscribe to Sync Streams +### 4. Subscribe to Sync Streams @@ -307,20 +308,20 @@ impl BackendConnector for MyBackendConnector { -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -* [reader](#reads) \- run statements reading from the database. -* [writer](/client-sdks/reference/kotlin#querying-items-powersync-getall) \- execute a read query every time source tables are modified. -* [writer](#mutations) \- write to the database. +* [`reader`](#reads) - run statements that read from the database. +* [`watch_statement`](#watching-queries) - execute a read query every time a dependent table changes. +* [`writer`](#mutations) - write to the database. ### Reads To obtain a connection suitable for reads, call and await `PowerSyncDatabase::reader()`. -The returned connection leased can be used as a `rusqlite::Connection` to run queries. +The returned lease can be used as a `rusqlite::Connection` to run queries. ```Rust async fn find(db: &PowerSyncDatabase, id: &str) -> Result<(), PowerSyncError> { @@ -333,6 +334,7 @@ async fn find(db: &PowerSyncDatabase, id: &str) -> Result<(), PowerSyncError> { println!("Found todo list: {id}, {name}"); } + Ok(()) } ``` @@ -344,10 +346,8 @@ The `watch_statement` method executes a read query whenever a change to a depend ### Mutations -Local writes on tables are automatically captured with triggers. To obtain a connection suitable for -writes, use the `PowerSyncDatabase::writer` method: - -The `execute` method executes a write query (INSERT, UPDATE, DELETE) and returns the results (if any). +Triggers capture local writes automatically. To obtain a connection suitable for writes, call and await +`PowerSyncDatabase::writer()`. Then call `execute` on the writer to run `INSERT`, `UPDATE`, or `DELETE` statements: ```Rust async fn insert_customer( @@ -364,12 +364,12 @@ async fn insert_customer( } ``` -If you're looking for transactions, use the [`transaction`](https://docs.rs/rusqlite/latest/rusqlite/struct.Connection.html#method.transaction) -method from `rusqlite` on `writer`. +For transactions, use the [`transaction`](https://docs.rs/rusqlite/latest/rusqlite/struct.Connection.html#method.transaction) +method from `rusqlite` on the writer. ## Configure Logging -The Rust SDK uses the `log` crate internally, so you can configure it with any backend, e.g. with +The Rust SDK uses the `log` crate internally, so you can configure it with any backend, for example `env_logger`: ```Rust @@ -387,7 +387,7 @@ For more usage examples including accessing connection status, monitoring sync p The Rust SDK does not currently support any higher-level SQL libraries, but we're investigating support for Diesel and sqlx. -Please reach out to us if you're interested in these or other integrations. +[Contact us](/resources/contact-us) if you are interested in these or other integrations. ## Troubleshooting diff --git a/client-sdks/reference/swift.mdx b/client-sdks/reference/swift.mdx index dbf037885..c98f48529 100644 --- a/client-sdks/reference/swift.mdx +++ b/client-sdks/reference/swift.mdx @@ -8,6 +8,7 @@ import SdkFeatures from '/snippets/sdk-features.mdx'; import SwiftInstallation from '/snippets/swift/installation.mdx'; import SwiftWatch from '/snippets/swift/basic-watch-query.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import LocalOnly from '/snippets/local-only-escape.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -33,12 +34,12 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill - Earlier versions of the Swift SDK (up to v1.13) shipped a PowerSync Kotlin XCFramework under the hood and abstracted it behind Swift protocols. + Up to v1.13, the Swift SDK wrapped a PowerSync Kotlin XCFramework 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). + From v1.14, the SDK has no Kotlin dependency. It is implemented natively in Swift and uses our [Rust core](https://github.com/powersync-ja/powersync-sqlite-core) for the sync protocol and SQLite extension. -### SDK Features +## SDK Features ## Installation @@ -47,19 +48,17 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). -**Example**: +**Example:** ```swift import Foundation @@ -106,14 +105,14 @@ let AppSchema = Schema(lists, todos) ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** ```swift let schema = AppSchema // Comes from the AppSchema defined above @@ -125,19 +124,19 @@ let db = PowerSyncDatabase( ### 3. Integrate with Your Backend -Create a connector to integrate with your backend. The PowerSync backend connector provides the connection between your application backend and the PowerSync managed database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. +1. Get an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. `PowerSyncBackendConnectorProtocol.fetchCredentials` - This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. +1. `PowerSyncBackendConnectorProtocol.fetchCredentials` - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. -2. `PowerSyncBackendConnectorProtocol.uploadData` - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +2. `PowerSyncBackendConnectorProtocol.uploadData` - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```swift import PowerSync @@ -169,7 +168,7 @@ Connect the PowerSync database to sync data with your backend: ```swift let connector = MyConnector() -try await powerSync.connect(connector: connector) +try await db.connect(connector: connector) ``` @@ -182,30 +181,30 @@ try await powerSync.connect(connector: connector) -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. The most commonly used CRUD functions to interact with your SQLite data are: -* [PowerSyncDatabase.get](/client-sdks/reference/swift#fetching-a-single-item-powersync-get-/-powersync-getoptional) - get (SELECT) a single row from a table. +* [PowerSyncDatabase.get](/client-sdks/reference/swift#fetching-a-single-item-powersync-get-/-powersync-getoptional) - get (`SELECT`) a single row from a table. -* [PowerSyncDatabase.getOptional](/client-sdks/reference/swift#fetching-a-single-item-powersync-get-/-powersync-getoptional) - get (SELECT) a single row from a table and return `null` if not found. +* [PowerSyncDatabase.getOptional](/client-sdks/reference/swift#fetching-a-single-item-powersync-get-/-powersync-getoptional) - get (`SELECT`) a single row from a table and return `nil` if not found. -* [PowerSyncDatabase.getAll](/client-sdks/reference/swift#querying-items-powersync-getall) - get (SELECT) a set of rows from a table. +* [PowerSyncDatabase.getAll](/client-sdks/reference/swift#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. -* [PowerSyncDatabase.watch](/client-sdks/reference/swift#watching-queries-powersync-watch) - execute a read query every time source tables are modified. +* [PowerSyncDatabase.watch](/client-sdks/reference/swift#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. -* [PowerSyncDatabase.execute](/client-sdks/reference/swift#mutations-powersync-execute) - execute a write (INSERT/UPDATE/DELETE) query. +* [PowerSyncDatabase.execute](/client-sdks/reference/swift#mutations-powersync-execute) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item (PowerSync.get / PowerSync.getOptional) -The `get` method executes a read-only (SELECT) query and returns a single result. It throws an exception if no result is found. Use `getOptional` to return a single optional result (returns `null` if no result is found). +The `get` method executes a read-only (SELECT) query and returns a single result. It throws an exception if no result is found. Use `getOptional` to return a single optional result (returns `nil` if no result is found). ```swift -// Find a list item by ID -func getList(_ id: String) async throws { - try await self.db.getAll( +// Find a list by ID +func getList(_ id: String) async throws -> ListContent { + try await db.get( sql: "SELECT * FROM \(LISTS_TABLE) WHERE id = ?", parameters: [id], mapper: { cursor in @@ -226,8 +225,8 @@ The `getAll` method executes a read-only (SELECT) query and returns a set of row ```swift // Get all lists -func getLists() async throws { - try await self.db.getAll( +func getLists() async throws -> [ListContent] { + try await db.getAll( sql: "SELECT * FROM \(LISTS_TABLE)", parameters: [], mapper: { cursor in @@ -279,7 +278,7 @@ func deleteTodo(id: String) async throws { ## Configure Logging -You can include your own Logger that must conform to the [LoggerProtocol](https://powersync-ja.github.io/powersync-swift/documentation/powersync/loggerprotocol) as shown here. +You can supply your own logger. It must conform to the [LoggerProtocol](https://powersync-ja.github.io/powersync-swift/documentation/powersync/loggerprotocol): ```swift let logger = DefaultLogger(minSeverity: .debug) @@ -355,7 +354,7 @@ PowerSync officially supports the [GRDB](/client-sdks/orms/swift/grdb) library f Additionally, [Asier G. Morato](https://github.com/asiergmorato) contributed a [Swift Data integration](https://github.com/powersync-community/swift-data) for PowerSync, allowing Swift Data models to be persisted and synced through a PowerSync database. -Note that the integration is community-owned and not officially supported by PowerSync. +The integration is community-owned and not officially supported by PowerSync. ## Troubleshooting diff --git a/client-sdks/reference/tauri.mdx b/client-sdks/reference/tauri.mdx index 636380fe3..26232c8d1 100644 --- a/client-sdks/reference/tauri.mdx +++ b/client-sdks/reference/tauri.mdx @@ -9,6 +9,7 @@ import TauriInstallation from '/snippets/tauri/installation.mdx'; import JavaScriptAsyncWatch from '/snippets/basic-watch-query-javascript-async.mdx'; import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-callback.mdx'; import GenerateSchemaAutomatically from '/snippets/generate-schema-automatically.mdx'; +import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; import MutationConfirmationWithReturning from '/snippets/javascript-mutation-confirmation-returning.mdx'; import SubscribeSyncStreamsIntro from '/snippets/subscribe-sync-streams-intro.mdx'; import SubscribeSyncStreamsOutro from '/snippets/subscribe-sync-streams-outro.mdx'; @@ -45,7 +46,7 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill There are [known limitations](#limitations) currently. -### SDK Features +## SDK Features @@ -55,23 +56,21 @@ Install the PowerSync Agent Skills with: npx skills add powersync-ja/agent-skill ## Getting Started -**Prerequisites**: To sync data between your client-side app and your backend source database, you must have completed the necessary setup for PowerSync, which includes connecting your source database to the PowerSync Service and deploying Sync Streams (steps 1-4 in the [Setup Guide](/intro/setup-guide)). +**Prerequisites:** Before you start, connect your source database to the PowerSync Service and deploy Sync Streams. These are steps 1-4 in the [Setup Guide](/intro/setup-guide). ### 1. Define the Client-Side Schema -import SdkClientSideSchema from '/snippets/sdk-client-side-schema.mdx'; - -The types available are `text`, `integer` and `real`. These should map directly to the values produced by your [Sync Streams](/sync/streams/overview). If a value doesn't match, it is cast automatically. For details on how backend source database types are mapped to the SQLite types, see [Types](/sync/types). +The available column types are `text`, `integer`, and `real`. These should match the values produced by your Sync Streams. If a value does not match, it is cast automatically. For details on how source database types map to SQLite types, see [Types](/sync/types). The Tauri SDK inherits the same APIs from the JavaScript Web SDK via `@powersync/common`, with a few exceptions detailed below. See the [Web SDK schema definition section](/client-sdks/reference/javascript-web#1-define-the-client-side-schema) for more advanced examples. -**Example**: +**Example:** ```js // AppSchema.ts @@ -110,14 +109,14 @@ export type ListRecord = Database['lists']; ``` - **Note**: No need to declare a primary key `id` column, as PowerSync will automatically create this. + You do not need to declare an `id` column. PowerSync creates it automatically. ### 2. Instantiate the PowerSync Database -Next, you need to instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your [Sync Streams](/sync/streams/overview). In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline. +Next, instantiate the PowerSync database. PowerSync streams changes from your backend source database into the client-side SQLite database, based on your Sync Streams. Your app reads from and writes to this local database whether the user is online or offline. -**Example**: +**Example:** ```js import { PowerSyncTauriDatabase } from '@powersync/tauri-plugin'; @@ -163,7 +162,7 @@ async fn connect( } ``` -Ensure the command is registered by including it in the invoke handler with +Register the command by including it in the invoke handler with `tauri::generate_handler![connect]`. You can then invoke that command from your JavaScript code to connect: @@ -181,23 +180,23 @@ async function connect(db: PowerSyncTauriDatabase) { ### 3. Integrate with Your Backend -The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to: +The backend connector connects the PowerSync client SDK to your application backend. The SDK uses it to: -1. Retrieve an auth token to connect to the PowerSync instance. -2. Upload client-side writes to your backend API. Any writes that are made to the SQLite database are placed into an upload queue by the PowerSync Client SDK and automatically uploaded to your app backend (where you apply those changes to the backend source database) when the user is connected. +1. Get an auth token to connect to the PowerSync instance. +2. Upload client-side writes to your backend API. The SDK places every write to the SQLite database in an upload queue and uploads the queue to your backend when the user is connected. Your backend then applies the changes to the source database. At the moment, backend connectors for the Tauri SDK must be implemented in Rust. This allows the connector to be used across multiple windows and even when no JavaScript is running. -Please [let us know](/resources/contact-us) if you want to implement a backend connector in JavaScript. +[Let us know](/resources/contact-us) if you want to implement a backend connector in JavaScript. -Accordingly, the connector must implement two methods: +The connector must implement two methods: -1. `fetch_credentials` \- This method is automatically invoked by the PowerSync Client SDK to obtain authentication credentials. The SDK caches credentials internally and only calls this method when needed (e.g. on initial connection or when the token is near expiry). See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details, and [Authentication Setup](/configuration/auth/overview) for instructions on how the credentials should be generated. -2. `upload_data` \- This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app's backend API. You need to implement how those writes are processed and uploaded in this method. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for details on triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for considerations on the app backend implementation. +1. `fetch_credentials` - The SDK calls this method to get authentication credentials. It caches the credentials and calls the method again only when needed, for example on the first connection or when the token is near expiry. See [When `fetchCredentials()` is Called](/configuration/app-backend/client-side-integration#when-fetchcredentials-is-called) for details and [Authentication Setup](/configuration/auth/overview) for how to generate credentials. +2. `upload_data` - The SDK calls this method whenever it has client-side writes to upload to your backend API. Implement how those writes are processed and uploaded. See [When `uploadData()` is Called](/configuration/app-backend/client-side-integration#when-uploaddata-is-called) for triggers, throttling, and retry behavior, and [Writing Client Changes](/handling-writes/writing-client-changes) for the app backend implementation. -**Example**: +**Example:** ```Rust struct MyBackendConnector { @@ -241,7 +240,7 @@ impl BackendConnector for MyBackendConnector { -## Using PowerSync: CRUD functions +## Using PowerSync: CRUD Functions Once the PowerSync database is connected and your streams have synced, the data is in the local SQLite database. @@ -251,10 +250,10 @@ Once the PowerSync database is connected and your streams have synced, the data The most commonly used CRUD functions to interact with your SQLite data are: -- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (SELECT) a single row from a table. -- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (SELECT) a set of rows from a table. -- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time source tables are modified. -- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (INSERT/UPDATE/DELETE) query. +- [PowerSyncDatabase.get](/client-sdks/reference/javascript-web#fetching-a-single-item) - get (`SELECT`) a single row from a table. +- [PowerSyncDatabase.getAll](/client-sdks/reference/javascript-web#querying-items-powersync-getall) - get (`SELECT`) a set of rows from a table. +- [PowerSyncDatabase.watch](/client-sdks/reference/javascript-web#watching-queries-powersync-watch) - execute a read query every time a dependent table changes. +- [PowerSyncDatabase.execute](/client-sdks/reference/javascript-web#mutations-powersync-execute-powersync-writetransaction) - execute a write (`INSERT`/`UPDATE`/`DELETE`) query. ### Fetching a Single Item @@ -273,7 +272,7 @@ export const findList = async (id) => { The [getAll](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#getall) method returns a set of rows from a table. ```js -// Get all list IDs +// Get all lists export const getLists = async () => { const results = await db.getAll('SELECT * FROM lists'); return results; @@ -293,26 +292,23 @@ The [watch](https://powersync-ja.github.io/powersync-js/common/interfaces/Common -For advanced watch query features like incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). +For advanced watch query features such as incremental updates and differential results, see [Live Queries / Watch Queries](/client-sdks/watch-queries). ### Mutations (PowerSync.execute, PowerSync.writeTransaction) The [execute](https://powersync-ja.github.io/powersync-js/common/interfaces/CommonPowerSyncDatabase#execute) method can be used for executing single SQLite write statements. ```js -// Delete a list item by ID +// Delete a list by ID export const deleteList = async (id) => { - const result = await db.execute('DELETE FROM lists WHERE id = ?', [id]); - return TodoList.fromRow(results); -} + await db.execute('DELETE FROM lists WHERE id = ?', [id]); +}; -// OR: using a transaction -const deleteList = async (id) => { +// OR: delete the list and its todos in one transaction +export const deleteListWithTodos = async (id) => { await db.writeTransaction(async (tx) => { - // Delete associated todos - await tx.execute(`DELETE FROM ${TODOS_TABLE} WHERE list_id = ?`, [id]); - // Delete list record - await tx.execute(`DELETE FROM ${LISTS_TABLE} WHERE id = ?`, [id]); + await tx.execute('DELETE FROM todos WHERE list_id = ?', [id]); + await tx.execute('DELETE FROM lists WHERE id = ?', [id]); }); }; ``` diff --git a/snippets/generate-schema-automatically.mdx b/snippets/generate-schema-automatically.mdx index 91e0f20f6..3d832c2b0 100644 --- a/snippets/generate-schema-automatically.mdx +++ b/snippets/generate-schema-automatically.mdx @@ -1,10 +1,8 @@ **Generate schema automatically** - In the [PowerSync Dashboard](https://dashboard.powersync.com/), select your project and instance and click the **Connect** button in the top bar to generate the client-side schema in your preferred language. The schema will be generated based on your Sync Streams. + In the [PowerSync Dashboard](https://dashboard.powersync.com/), select your project and instance and click the **Connect** button in the top bar to generate the client-side schema in your preferred language. The schema is generated from your Sync Streams. The [CLI](/tools/cli) offers the same function. - Similar functionality exists in the [CLI](/tools/cli). - - **Note:** The generated schema will not include an `id` column, as the client SDK automatically creates an `id` column of type `text`. Consequently, it is not necessary to specify an `id` column in your schema. For additional information on IDs, refer to [Client ID](/sync/advanced/client-id). + The generated schema does not include an `id` column. The client SDK creates an `id` column of type `text` automatically, so you do not need to declare it. See [Client ID](/sync/advanced/client-id) for details. diff --git a/snippets/local-only-escape.mdx b/snippets/local-only-escape.mdx index e4cdfbb55..81df892d7 100644 --- a/snippets/local-only-escape.mdx +++ b/snippets/local-only-escape.mdx @@ -1,3 +1,3 @@ - **Note**: This section assumes you want to use PowerSync to sync your backend source database with SQLite in your app. If you only want to use PowerSync to manage your local SQLite database without sync, instantiate the PowerSync database without calling `connect()` and refer to our [Local-Only](/client-sdks/advanced/local-only-usage) guide. - \ No newline at end of file + This section assumes that you use PowerSync to sync your backend source database with SQLite in your app. To manage a local SQLite database without sync, instantiate the PowerSync database without calling `connect()` and see the [Local-Only](/client-sdks/advanced/local-only-usage) guide. + diff --git a/snippets/sdk-client-side-schema.mdx b/snippets/sdk-client-side-schema.mdx index a922d247b..5ecf6a4df 100644 --- a/snippets/sdk-client-side-schema.mdx +++ b/snippets/sdk-client-side-schema.mdx @@ -1 +1,3 @@ -This refers to the schema for the managed SQLite database exposed by the PowerSync Client SDKs, that your app can read from and write to. The schema is applied when the database is instantiated (as we'll show in the next step) — no migrations are required. \ No newline at end of file +The client-side schema defines the tables and columns of the SQLite database that the PowerSync client SDK manages and that your app reads from and writes to. It is usually derived from your backend database schema and your [Sync Streams](/sync/streams/overview), and it can also include [local-only tables](/client-sdks/advanced/local-only-usage). You apply the schema when you instantiate the database in the next step. + +Schema migrations are not required. The SDK syncs schemaless data and applies the schema to that data with SQLite views. The exception is [raw tables](/client-sdks/advanced/raw-tables), which you create and migrate yourself. diff --git a/snippets/sdk-features.mdx b/snippets/sdk-features.mdx index 9edb94f03..a400892a2 100644 --- a/snippets/sdk-features.mdx +++ b/snippets/sdk-features.mdx @@ -2,4 +2,4 @@ * **Direct access to a local SQLite database**: Data is stored locally, so apps can read and write instantly without network calls. This enables offline support and faster user interactions. * **Asynchronous background execution**: The SDK performs database operations in the background to avoid blocking the application’s main thread. This means that apps stay responsive, even during heavy data activity. * **Query subscriptions for live updates**: The SDK supports query subscriptions that automatically push real-time updates to client applications as data changes, keeping your UI reactive and up to date. -* **Automatic schema management**: PowerSync syncs schemaless data and applies a client-defined schema using SQLite views. This architecture means that PowerSync SDKs can handle schema changes gracefully without requiring explicit migrations on the client-side. \ No newline at end of file +* **Automatic schema management**: PowerSync syncs schemaless data and applies a client-defined schema using SQLite views. This architecture means that PowerSync SDKs handle schema changes without explicit migrations on the client side. \ No newline at end of file diff --git a/snippets/subscribe-sync-streams-outro.mdx b/snippets/subscribe-sync-streams-outro.mdx index 1da1c9516..52f4a7500 100644 --- a/snippets/subscribe-sync-streams-outro.mdx +++ b/snippets/subscribe-sync-streams-outro.mdx @@ -1 +1 @@ -After you unsubscribe, the synced data stays in the local database for the stream's TTL (24 hours by default). If the app subscribes again within that time, the data is already available. Framework hooks, per-subscription sync status, custom TTLs, priority overrides, and connection parameters are covered in [Client-Side Usage](/sync/streams/client-usage). +After you unsubscribe, the synced data stays in the local database for the stream's time-to-live (TTL), which is 24 hours by default. If the app subscribes again within that time, the data is already available. See [Client-Side Usage](/sync/streams/client-usage) for framework hooks, per-subscription sync status, custom TTLs, priority overrides, and connection parameters.