DATE:
AUTHOR:
PowerSync Product Team
Flutter SDK Flutter Packages/Libraries

PowerSync Dart/Flutter SDK v2.0

DATE:
AUTHOR: PowerSync Product Team

We've released v2.0 of the PowerSync Dart/Flutter SDK. This release is a new major version and is the result of a substantial internal refactor that simplifies the SDK structure, improves performance, makes it easier for us to add new features and improves support for standalone (non-Flutter) Dart apps.

v2.0 has breaking changes, but these should only affect a small subset of users. If you currently use the standard powersync package without a custom open factory, encryption, or direct sqlite3 / sqlite_async imports, the upgrade should be straightforward. Review the Breaking changes section below for what may apply to you.

What's new

  • Single package for all Dart platforms: powersync now covers Flutter, CLI, and server-side Dart. We removed the separate powersync_core, powersync_sqlcipher, and powersync_flutter_libs packages.

  • Native: multi-engine and multi-isolate database sharing: The rewritten connection pool lets you open the same database safely across isolates or multiple Flutter engines.

  • Web: OPFS by default on Chrome and Firefox: New databases use OPFS instead of IndexedDB for stronger SQLite performance on the web. Existing databases keep their current storage.

  • Built-in encryption: EncryptionOptions is part of the main powersync package; you no longer need to add the separate powersync_sqlcipher package.

  • New APIs: watchUnthrottled / onChangeUnthrottled for backpressure-aware change streams, and abortableReadLock / abortableWriteLock so you can cancel lock acquisition programmatically.

  • Updated dependencies: The SDK now supports sqlite3 3.x, sqlite3_web 0.7.x, sqlite_async 0.14.0, and the latest drift.

In detail

Single package for all Dart platforms

powersync is now the only package you need, regardless of whether you're building a Flutter app, a CLI tool, or a server-side Dart service. We consolidated powersync_core, powersync_sqlcipher, and powersync_flutter_libs into it.

Previously, different platforms and features required separate packages, which made the dependency tree harder to manage and the API surface harder to navigate.

SQLite loading is also fully automatic via build hooks. You no longer need powersync_flutter_libs or manual initialization.

Native: query performance and multi-engine database sharing

On native platforms, connection pooling now runs through a Rust-backed shared implementation. Queries run faster because connections are shared across isolates in native code rather than pinned to dedicated Dart worker isolates.

You can also now open the same database safely from multiple isolates or Flutter engines (for example, a UI isolate and a background worker). Multiple databases automatically share write locks and table updates. Note that you should only .connect() to PowerSync from one of those instances.

The tradeoff is that Dart-defined SQL functions are no longer supported. The pool lends connections across isolates, and Dart callbacks can only be called from the isolate that registered them. More about this in the original proposal.

Web: OPFS by default on Chrome and Firefox, single worker

On Chrome and Firefox, new databases now use OPFS (Origin Private File System) instead of IndexedDB. OPFS delivers better performance for SQLite on the web. Existing databases on IndexedDB are not migrated — they continue using IndexedDB.

On Safari, OPFS needs these headers on your HTTP responses:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Additionally, we merged the sync and database workers have into a single shared worker powersync_db.worker.js), improving performance and reducing the total compiled output size.

Updated encryption setup

Encryption is now part of the main powersync package, and we removed the separate powersync_sqlcipher package. v2.0 uses SQLite3MultipleCiphers sqlite3mc) instead of SQLCipher.

Upgrading from SQLCipher? Remove your powersync_sqlcipher dependency and follow the steps below. See the encryption docs for the full migration path.

To set up encryption:

Native platforms: Add this to your pubspec.yaml (with pub workspaces, add it to the root pubspec.yaml, not the app's):

hooks:
  user_defines:
    sqlite3:
      source: sqlite3mc

Web: Download the encryption-capable WASM binary into your web/ directory:

dart run powersync:setup_web --encryption

All platforms: Pass EncryptionOptions to the constructor:

final db = PowerSyncDatabase(
  schema: schema,
  path: path,
  encryption: EncryptionOptions(key: 'my secret key'),
);

More details are in the encryption docs.

New: Unthrottled watch streams and abortable locks

watchUnthrottled and onChangeUnthrottled: Variants of watch and onChange that emit on every change without a fixed delay between notifications. Flow is controlled only by back-pressure from paused subscriptions, giving you full control over how the stream is consumed.

abortableReadLock and abortableWriteLock: Acquire read/write connections using a Future<void> abort signal instead of a fixed Duration timeout. This lets you compose cancellation — for example, cancel a pending lock acquisition when a widget is disposed.

Removed legacy Dart sync client

The legacy Dart sync client has been removed. The Rust-based sync client — already the default for several months — is now the only implementation. This reduces app size and removes legacy code.

Breaking changes

1. Consolidated packages: update your dependencies

The powersync package now covers all Dart platforms (Flutter, CLI, server-side). We removed these packages:

  • powersync_core: Update all imports from package:powersync_core/... to package:powersync/.... This affects you if you use the attachments API or import powersync_core directly.

  • powersync_sqlcipher: Encryption support is now included in the powersync package. See Updated encryption setup above.

  • powersync_flutter_libs: Build hooks load SQLite automatically; you do not need a separate libs package.

2. SQLite version upgrade: web users must update workers

v2.0 upgrades to sqlite3 3.x, sqlite3_web 0.7.x, and sqlite_async 0.14.0. drift already requires sqlite3 3.x. This upgrade also removes the workarounds you previously needed to run sqlite_async on non-Flutter Dart platforms.

If you use PowerSync on the web, download updated worker and sqlite3.wasm files after you upgrade. From your app folder, run:

dart run powersync:setup_web

For encryption on the web, pass the --encryption flag. See Updated encryption setup above.

3. Removed custom initialization APIs

We removed package:powersync/sqlite3_open.dart. SQLite now loads exclusively through build hooks.

We also removed AbstractPowerSyncOpenFactory and PowerSyncOpenFactory. The old factory hierarchy was hard to customize and produced confusing type errors in some setups. If you previously used AbstractPowerSyncOpenFactory to customize how databases open, use conditional imports for package:powersync/native.dart and package:powersync/web.dart and extend the platform-specific factory class directly:

// native_database.dart
import 'package:powersync/native.dart';

class MyCustomOpenFactory extends NativePowerSyncOpenFactory {
  // your customizations
}
// web_database.dart
import 'package:powersync/web.dart';

class MyCustomOpenFactory extends WebPowerSyncOpenFactory {
  // your customizations
}

4. Removed SQL functions and user-defined functions

You can no longer register user-defined SQL functions implemented in Dart. Functions provided by the native SQLite extension are unaffected. This is the direct tradeoff for the faster Rust-backed connection pool described in the section above (see the proposal for the technical background). If this affects you, please reach out.

Similarly, PowerSync previously registered SQL functions such as uuid and powersync_diff in the Dart layer. Those functions now live in the SQLite core extension and the SDK automatically registers them. We removed powersync_sleep and powersync_connection_name as part of this. None of our other SDKs expose them and we do not expect that they're meaningfully used outside our own internal tests.

5. Deprecated re-exports

The following imports are deprecated. They were re-exported packages, and broke auto-import suggestions and made it unclear which packages your app actually uses. Add each as a direct dependency instead and replace imports:

  • Replace package:powersync/sqlite_async.dart with package:sqlite_async/sqlite_async.dart

  • Replace package:powersync/sqlite3.dart with package:sqlite3/sqlite3.dart

  • Replace package:powersync/sqlite3_common.dart with package:sqlite3/common.dart

6. maxReaders has moved to SqliteOptions

The maxReaders parameter has moved from PowerSyncDatabase constructors to SqliteOptions. If you were setting it, pass it via SqliteOptions instead.

Getting started

New to PowerSync? Start with the Setup Guide and Dart SDK docs.

Upgrading from v1.x? Breaking changes should affect a small subset of users only. Review the section above to see which apply to you.

Feedback and help

Questions or issues with this version? Please share your feedback with us on Discord or open an issue on GitHub.

Powered by LaunchNotes