Skip to main content
This SDK is currently in an alpha release. It is not suitable for production use as breaking changes may still occur.

Supported Frameworks and Targets

The PowerSync .NET SDK supports:
  • .NET Versions: 6, 8, and 9
  • .NET Framework: Version 4.8 (requires additional configuration)
  • MAUI: Cross-platform support for Android, iOS, and Windows
  • WPF: Windows desktop applications
Current Limitations:
  • Blazor (web) platforms are not yet supported.
For more details, please refer to the package README.

SDK Features

  • Provides real-time streaming of database changes.
  • Offers direct access to the SQLite database, enabling the use of SQL on both client and server sides.
  • Provides watched queries that allow listening for live updates to data.
  • Eliminates the need for client-side database migrations as these are managed automatically.

Quickstart

For desktop/server/binary use-cases and WPF, add the PowerSync.Common NuGet package to your project:
dotnet add package PowerSync.Common --prerelease
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).

1. Define the Client-Side Schema

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.

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 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:
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();
    }
}

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:
  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.
Accordingly, the connector must implement two methods:
  1. 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.
  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 backend via your backend API. Therefore, in your implememtation, you need to define how your backend API is called. See Writing Client Changes for considerations on the app backend implementation.
Example:
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:
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.

Using PowerSync: CRUD functions

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.

Fetching a Single Item

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).
// Use db.Get() to fetch a single row:
Console.WriteLine(await db.Get<object>("SELECT powersync_rs_version();"));

Querying Items (PowerSync.GetAll)

The GetAll method returns a set of rows from a table.
// Or db.GetAll() to fetch all:
// Where List result is defined:
// record ListResult(string id, string name, string owner_id, string created_at);
Console.WriteLine(await db.GetAll<ListResult>("SELECT * FROM lists;"));

Watching Queries (PowerSync.Watch)

The Watch method executes a read query whenever a change to a dependent table is made.
// Use db.Watch() to watch queries for changes (await is used to wait for initialization):
<DotNetWatch />

Mutations (PowerSync.Execute)

The Execute method can be used for executing single SQLite write statements.
// 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())",
  [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:
using Microsoft.Extensions.Logging;
using PowerSync.Common.Client;

// Create a logger factory
ILoggerFactory 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
});

Additional Usage Examples

For more usage examples including accessing connection status, monitoring sync progress, and waiting for initial sync, see the Usage Examples page.

Troubleshooting

See Troubleshooting for pointers to debug common issues.

Supported Platforms

See Supported Platforms -> .NET SDK.

Upgrading the SDK

To upgrade to the latest version of the PowerSync package, run the below command in your project folder:
dotnet add package PowerSync.Common --prerelease
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