Overview
PowerSync provides multiple approaches to watching queries, each designed for different use cases and performance requirements:- Basic Watch Queries - These queries work across all SDKs, providing real-time updates when dependent tables change
- Incremental Watch Queries - Only emit updates when data actually changes, preventing unnecessary re-renders
- Differential Watch Queries - Provide detailed information about what specifically changed between result sets
Basic Watch Queries
PowerSync supports the following basic watch queries based on your platform. These APIs return query results whenever the underlying tables change and are available across all SDKs. Scroll horizontally to find your preferred platform/framework for an example:This method is only being maintained for backwards compatibility purposes. Use the improved
db.query.watch()
API instead (see Incremental Watch Queries below).Incremental Watch Queries
Basic watch queries can cause performance issues in UI frameworks like React because they return new data on every dependent table change, even when the actual data in the query hasn’t changed. This can lead to excessive re-renders as components receive updates unnecessarily. Incremental watch queries solve this by comparing result sets using configurable comparators and only emitting updates when the comparison detects actual data changes. These queries still query the SQLite DB under the hood on each dependent table change, but compare the result sets and only yield results if a change has been made.JavaScript Only: Incremental and differential watch queries are currently only available in the JavaScript SDKs starting from:
- Web v1.25.0
- React Native v1.23.1
- Node.js v0.8.1
WatchedQuery
class that comes with a better API in that it includes loading, fetching and error states, supports multiple listeners, automatic cleanup on PowerSync close, and the new updateSettings()
API for dynamic parameter changes. This is the preferred approach for JavaScript SDKs:Differential Watch Queries
Differential queries go a step further than incremental watched queries by computing and reporting diffs between result sets (added/removed/updated items) while preserving object references for unchanged items. This enables more precise UI updates.JavaScript Only: Incremental and differential watch queries are currently only available in the JavaScript SDKs starting from:
- Web v1.25.0
- React Native v1.23.1
- Node.js v0.8.1
For large result sets where re-running and comparing full query results becomes expensive, consider using trigger-based table diffs. See High Performance Diffs.
differentialWatch()
method uses a DEFAULT_ROW_COMPARATOR
. This comparator identifies (keys) each row by its id
column if present, or otherwise by the JSON string of the entire row. For row comparison, it uses the JSON string representation of the full row. This approach is generally safe and effective for most queries.
For some queries, performance could be improved by supplying a custom rowComparator
. Such as comparing by a hash
column generated or stored in SQLite. These hashes currently require manual implementation.
The Yjs Document Collaboration Demo
app showcases the use of
differential watch queries. New document updates are passed to Yjs for consolidation as they are synced. See the
implementation
here
for more details.
The WatchedQuery
Class
Both incremental and differential queries use the new WatchedQuery
class. This class, along with a new query
method allows building instances of WatchedQuery
s via the watch
and differentialWatch
methods:
- Automatically reprocesses itself if the PowerSync schema has been updated with
updateSchema
. - Automatically closes itself when the PowerSync client has been closed.
- Allows for the query parameters to be updated after instantiation.
- Allows shared listening to state changes.
- New
updateSettings
API for dynamic parameter updates (see below).
Query Sharing
WatchedQuery
instances can be shared across components:
Dynamic Parameter Updates
Update query parameters to affect all subscribers of the query:React Hook for External WatchedQuery Instances
When you need to share query instances across components or manage their lifecycle independently from component mounting, use theuseWatchedQuerySubscription
hook. This is ideal for global state management, query caching, or when multiple components need to subscribe to the same data: