Adopting PowerSync can simplify the architecture of your app by using a local SQLite database as the single source of truth for all data.
For a general discussion on how PowerSync fits into modern app architecture on Flutter, also see this blogpost.
Future and Stream classes from dart:async. Given how widely used these are
in the Dart ecosystem, PowerSync works well with all popular approaches for state management, such as:
- Providers with
package:provider: Create your database as aProviderand expose watched queries to child widgets withStreamProvider! The provider for databases shouldclose()the database indispose. - Providers with
package:riverpod: We mention relevant snippets below. - Dependency injection with
package:get_it: PowerSync databases can be registered withregisterSingletonAsync. Again, make sure toclose()the database in thedisposecallback. - The BLoC pattern with the
blocpackage: You can easily listen to watched queries in Cubits (although, if you find your Blocs and Cubits becoming trivial wrappers around database streams, consider justwatch()ing database queries in widgets directly. That doesn’t make your app less testable!). To simplify state management, avoid the use of hydrated blocs and cubits for state that depends on database queries. With PowerSync, regular data is already available locally and doesn’t need a second local cache.
Riverpod
We have a complete example on using PowerSync
with modern Flutter libraries like Riverpod, Drift and
auto_route.connect and
disconnect calls there, for instance by listening to the authentication state:
Running queries
To expose auto-updating query results, use aStreamProvider reading the database:
Waiting for sync
If you were awaitingwaitForFirstSync before, you can keep doing that: