- DATE:
- AUTHOR:
- PowerSync Product Team
Get High Performance Diffs in our JavaScript SDKs (Experimental)
PowerSync now supports trigger-based table diffs in our JavaScript SDKs — an experimental feature that provides a faster way to detect and compare row-level changes in large datasets.
Unlike differential watch queries, which re-run and compare entire result sets on every change, trigger-based diffs use SQLite triggers to capture inserts, updates, and deletes as they happen. This makes performance proportional to the number of rows changed, rather than the total result set size.
Why This Matters
Differential watch queries are flexible — they can handle multi-table queries, joins, and arbitrary SQL. But on large result sets (e.g., scanning ~10,000 rows just to detect a single new item), they can introduce significant overhead.
Trigger-based diffs are designed for cases where you only need to track changes on a single table. Instead of re-querying and comparing, PowerSync installs temporary SQLite triggers that record changes into a diff table. Your app can then react to these diffs directly.
In practice, this means:
• Large tables update more efficiently. You only process the rows that changed, not the full dataset.
• Write-time overhead, not read-time overhead. The extra work happens once per write operation, instead of every time a query result is updated.
• SQL-level filtering. You can skip recording certain changes at the trigger level.
Availability
High Performance Diffs are available in our JavaScript SDKs:
• Web v1.26.0
• React Native v1.24.0
• Node.js v0.10.0
The APIs live under db.triggers
and are experimental. Expect changes as we gather feedback.
Using Trigger-Based Diffs
The recommended entry point is the trackTableDiff
API. It:
Sets up temporary triggers for the given source table.
Exposes a DIFF table alias to query recent changes.
Manages lifecycle and locking automatically.
Cleans up when you call
stop()
.
const stop = await db.triggers.trackTableDiff({
// PowerSync source table/view to trigger and track changes from.
// This should be present in the PowerSync database's schema.
source: 'todos',
// Specifies which columns from the source table to track in the diff records.
// Defaults to all columns in the source table.
// Use an empty array to track only the ID and operation.
columns: ['list_id'],
// Required WHEN clause per operation to filter inside the trigger. Use 'TRUE' to track all.
when: { INSERT: `json_extract(NEW.data, '$.list_id') = '${firstList.id}'` },
onChange: async (context) => {
// // Fetches the todo records that were inserted during this diff
const newTodos = await context.getAll(/* sql */ `
SELECT todos.*
FROM DIFF
JOIN todos ON DIFF.id = todos.id
`);
// Handle new todos here
}
});
// Later, dispose triggers and internal resources
await stop();
For advanced use cases (e.g., buffering changes to process them later), you can use the lower-level createDiffTrigger
API.
You can find more details about these APIs in our docs.
Share Your Feedback 
Because this is an experimental feature, we’re actively looking for feedback on the API design and developer experience.
Please share your thoughts and experience on our Discord!