Where to Start
Syncing Only What the App Needs
Every table, row, and column selected by your Sync Streams is stored in buckets and downloaded by each subscribed client it applies to. Global streams return the same data to every client that subscribes. If a global stream hasauto_subscribe: true, every connecting client downloads its data. Remove tables and columns your app does not use, and filter out rows it no longer needs, such as archived or historical records. Selecting fewer columns makes each row smaller, which reduces both stored and downloaded data. It does not reduce the number of sync operations by itself.
Keeping Large Files Out of Synced Rows
Large columns, such as base64-encoded files, long JSON documents, or binary data, make every download of those rows larger. If the row changes often or syncs to many clients, that cost repeats. Store files in object storage, such as Amazon S3 or Supabase Storage, and sync only small metadata records that reference them. The SDKs include attachment helpers that manage uploads, downloads, and local caching for this pattern.Compacting and Defragmenting
Buckets hold an operations history so that existing clients can download only the changes since their last sync. Over time, that history can grow much larger than the current set of rows. This increases hosted data and makes new clients download more data during their initial sync. Two maintenance operations reduce it:- Compacting removes history that later operations have made redundant. For example, when a later operation replaces an earlier version of the same row, clients no longer need the earlier row data. PowerSync Cloud compacts all buckets automatically once per day. You can also trigger it from the instance’s Settings view in the Dashboard or with the CLI. For self-hosted deployments, run the Docker image’s
compactcommand manually or on a schedule. - Defragmenting handles what compacting cannot. The oldest remaining
PUToperation in a bucket prevents PowerSync from fully compacting the operations that follow it. Buckets that mix rarely changed rows with frequently updated rows can therefore keep accumulating history. Defragmenting updates, or “touches,” rows so compacting can remove the earlier history. Use the Defragment button in the same Settings view, or update the affected source rows on a schedule. Existing clients must re-sync each touched row, so choose a frequency that fits your update patterns.
Reducing Bucket Fan-Out
A row is stored and synced once for every bucket it belongs to. If the same row belongs to ten buckets, PowerSync stores and syncs it ten times. Streams that place the same rows in many buckets therefore multiply both stored and downloaded data. See Reducing Bucket Count.Reducing Data Synced
Large data synced totals often come from devices downloading the same data repeatedly, not from new data being created. Before optimizing your Sync Streams, check whether clients are repeating their initial sync. A normal reconnect resumes from the client’s saved sync position and downloads only newer operations.Avoiding Unnecessary Full Re-Syncs
A client that loses its local database must download all its subscribed data from scratch. This is expected after a fresh installation. If the same device repeatedly starts from scratch, check for these causes:- The app calls
disconnectAndClear()when a user signs out. This clears the local database, so the next session starts from nothing. Clearing is appropriate when another user can access the device or your security requirements prohibit keeping the data. If the same user will return and keeping their data is safe,disconnect()closes the sync connection without clearing the database. - The browser clears or cannot retain the web client’s storage. Private browsing modes and browser storage policies can cause the app to lose its database between sessions.
- App code deletes or recreates the database file as part of its own lifecycle.
Avoiding Reconnect Loops
A reconnect does not normally trigger a full download because the client resumes from its saved sync position. However, an app that reconnects every few minutes can create hundreds of sync sessions per day. If each session downloads data, those transfers add up. Open onePowerSyncDatabase per session and call .connect() once instead of reconnecting when the window gains focus or whenever a token refreshes. To confirm this pattern in your instance logs, see Repetitive Syncing by the Same User.
On-Demand Data with Sync Streams
Data that does not need to be available while offline does not have to live on every device. With Sync Streams, your app can subscribe only while it needs the data, such as while a specific screen is open. After the app unsubscribes and the subscription’s cache time expires, PowerSync removes data that is no longer covered by another stream from the local database. Streams withauto_subscribe: true behave like always-on data, so use them only for data that every connecting client needs.
Writes That Do Not Change Data
PowerSync processes source changes at the row level. Rewriting a row selected by your Sync Streams can create a new operation even when its selected values do not change. Even a no-op update such asUPDATE tasks SET id = id can create an operation for every affected row. A nightly job that rewrites an entire table can therefore make active clients download those rows again the next day while also growing the operations history. Restrict batch jobs to rows whose values need to change, and confirm their effect in your instance logs.