Add --prerelease while this package is in alpha. To install a specific version, use --version instead: dotnet add package PowerSync.Common --version 0.0.6-alpha.1
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 Rules (steps 1-4 in the Setup Guide).
This refers to the 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) — .
Generate schema automaticallyIn the PowerSync Dashboard, 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 Rules.Similar functionality exists in the 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.
You can use this example as a reference when defining your schema.The types available are text, integer and real. These should map directly to the values produced by the Sync Rules. 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.
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 Rules. In your client-side app, you can read from and write to the local SQLite database, whether the user is online or offline.Example:The initialization syntax differs slightly between the Common and MAUI SDKs:
Common
MAUI
Copy
using PowerSync.Common.Client;class Demo{ static async Task Main() { var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions { Database = new SQLOpenOptions { DbFilename = "tododemo.db" }, Schema = AppSchema.PowerSyncSchema, }); await db.Init(); }}
Copy
using PowerSync.Common.Client;using PowerSync.Common.MDSQLite;using PowerSync.Maui.SQLite;class Demo{ static async Task Main() { // Ensures the DB file is stored in a platform appropriate location var dbPath = Path.Combine(FileSystem.AppDataDirectory, "maui-example.db"); var factory = new MAUISQLiteDBOpenFactory(new MDSQLiteOpenFactoryOptions() { DbFilename = dbPath }); var Db = new PowerSyncDatabase(new PowerSyncDatabaseOptions() { Database = factory, // Supply a factory Schema = AppSchema.PowerSyncSchema, }); await db.Init(); }}
The PowerSync backend connector provides the connection between your application backend and the PowerSync client-side managed SQLite database. It is used to:
Retrieve an auth token to connect to the PowerSync instance.
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.
Accordingly, the connector must implement two methods:
PowerSyncBackendConnector.FetchCredentials - This method will be automatically invoked by the PowerSync Client SDK every couple of minutes to obtain authentication credentials. See Authentication Setup for instructions on how the credentials should be generated.
PowerSyncBackendConnector.UploadData - This method will be automatically invoked by the PowerSync Client SDK whenever it needs to upload client-side writes to your app backend via your backend API. Therefore, in your implementation, you need to define how your backend API is called. See Writing Client Changes for considerations on the app backend implementation.
Example:
Copy
using System;using System.Collections.Generic;using System.Net.Http;using System.Text;using System.Text.Json;using System.Threading.Tasks;using PowerSync.Common.Client;using PowerSync.Common.Client.Connection;using PowerSync.Common.DB.Crud;public class MyConnector : IPowerSyncBackendConnector{ private readonly HttpClient _httpClient; // User credentials for the current session public string UserId { get; private set; } // Service endpoints private readonly string _backendUrl; private readonly string _powerSyncUrl; private string? _clientId; public MyConnector() { _httpClient = new HttpClient(); // In a real app, this would come from your authentication system UserId = "user-123"; // Configure your service endpoints _backendUrl = "https://your-backend-api.example.com"; _powerSyncUrl = "https://your-powersync-instance.powersync.journeyapps.com"; } public async Task<PowerSyncCredentials?> FetchCredentials() { try { // Implement fetchCredentials to obtain a JWT from your authentication service. // See https://docs.powersync.com/configuration/auth/overview var authToken = "your-auth-token"; // Use a development token (see Authentication Setup https://docs.powersync.com/configuration/auth/development-tokens) to get up and running quickly // Return credentials with PowerSync endpoint and JWT token return new PowerSyncCredentials(_powerSyncUrl, authToken); } catch (Exception ex) { Console.WriteLine($"Error fetching credentials: {ex.Message}"); throw; } } public async Task UploadData(IPowerSyncDatabase database) { // Get the next transaction to upload CrudTransaction? transaction; try { transaction = await database.GetNextCrudTransaction(); } catch (Exception ex) { Console.WriteLine($"UploadData Error: {ex.Message}"); return; } // If there's no transaction, there's nothing to upload if (transaction == null) { return; } // Get client ID if not already retrieved _clientId ??= await database.GetClientId(); try { // Convert PowerSync operations to your backend format var batch = new List<object>(); foreach (var operation in transaction.Crud) { batch.Add(new { op = operation.Op.ToString(), // INSERT, UPDATE, DELETE table = operation.Table, id = operation.Id, data = operation.OpData }); } // Send the operations to your backend var payload = JsonSerializer.Serialize(new { batch }); var content = new StringContent(payload, Encoding.UTF8, "application/json"); HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content); response.EnsureSuccessStatusCode(); // Mark the transaction as completed await transaction.Complete(); } catch (Exception ex) { Console.WriteLine($"UploadData Error: {ex.Message}"); throw; } }}
With your database instantiated and your connector ready, call connect to start syncing data with your backend:
Copy
await db.Connect(new MyConnector());await db.WaitForFirstSync(); // Optional, to wait for a complete snapshot of data to be available
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() refer to our Local-Only guide.
Once the PowerSync instance is configured you can start using the SQLite DB functions.The most commonly used CRUD functions to interact with your SQLite data are:
PowerSyncDatabase.Get - get (SELECT) a single row from a table.
PowerSyncDatabase.GetAll - get (SELECT) a set of rows from a table.
PowerSyncDatabase.Watch - execute a read query every time source tables are modified.
PowerSyncDatabase.Execute - execute a write (INSERT/UPDATE/DELETE) query.
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).
Copy
// Define a result type with properties matching the schema columns (some columns omitted here for brevity)// public class ListResult { public string id; public string name; public string owner_id; ... }var list = await db.Get<ListResult>("SELECT * FROM lists WHERE id = ?", [listId]);
The GetAll method returns a set of rows from a table.
Copy
// Define a result type with properties matching the schema columns (some columns omitted here for brevity)// public class ListResult { public string id; public string name; public string owner_id; ... }var lists = await db.GetAll<ListResult>("SELECT * FROM lists");
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:
Copy
using Microsoft.Extensions.Logging;using PowerSync.Common.Client;// Create a logger factoryILoggerFactory loggerFactory = LoggerFactory.Create(builder =>{ builder.AddConsole(); // Enable console logging builder.SetMinimumLevel(LogLevel.Information); // Set minimum log level});var logger = loggerFactory.CreateLogger("PowerSyncLogger");var db = new PowerSyncDatabase(new PowerSyncDatabaseOptions{ Database = new SQLOpenOptions { DbFilename = "powersync.db" }, Schema = AppSchema.PowerSyncSchema, Logger = logger});
Add --prerelease while this package is in alpha. To install a specific version, use --version instead: dotnet add package PowerSync.Common --version 0.0.6-alpha.1