Skip to main content
To ensure consistency, it is important that the PowerSync Service does not interpret the same source row in different ways after updating to a new version. At the same time, we want to fix bugs or other inaccuracies that have accumulated during the development of the Service.

Overview

To make this trade‑off explicit, you choose whether to keep the existing behavior or turn on newer fixes that slightly change how data is processed. Use the config block in your Sync Config YAML to choose the behavior. There are two ways to turn fixes on:
  1. Set an edition to enable the full set of fixes for that edition. This is the recommended approach for new projects.
  2. Toggle individual options for more fine‑grained control.
For older projects, the previous behavior remains the default. New projects should enable all current fixes.

Configuration

For new projects, it is recommended to enable all current fixes by setting edition: <edition>:
Or, specify options individually:

Sync Streams Requirement

New Sync Streams configurations should use edition: 3, which enables the new compiler with an expanded SQL feature set (including JOIN, CTEs, multiple queries per stream, BETWEEN, CASE, and more):
Upgrading from alpha: If you have existing Sync Streams using edition: 2, upgrade to edition: 3 to enable the new compiler with an expanded SQL feature set (including JOIN, CTEs, multiple queries per stream, BETWEEN, CASE, and more). See Supported SQL for the full list of supported features.

Storage Version

A storage version tells the PowerSync Service how to organize prepared sync data in the bucket storage database. Changing the version does not rewrite the current data in place. When you next deploy the Sync Config, PowerSync prepares a new copy using the selected version. Clients continue using the current copy until the new one is ready. This avoids taking the instance offline for a bucket storage migration.

Optional config.storage_version

You can choose the bucket storage version in the config block:

When to Set storage_version Explicitly

When you omit storage_version, the PowerSync Service uses its configured default. Self-hosted bucket storage defaults to version 2 unless you set storage.default_storage_version in service.yaml. PowerSync Cloud manages this setting for you. Set storage_version when you need to:
  • Use incremental reprocessing or S3 bucket storage, which require version 4.
  • Keep an existing Sync Config on version 2 while you prepare for the version 4 deployment.
  • Prepare for a Service downgrade. Select a version supported by the older Service, deploy the Sync Config, and wait for the new copy to finish before downgrading.
For self-hosted deployments, you can make version 4 the default for newly deployed Sync Configs:
service.yaml
Changing this setting affects only later Sync Config deployments. Redeploy an existing config to move it to version 4. The first version 4 deployment reads all selected source data and prepares a new copy.

Supported Production Versions

A stable format means future Service versions can continue reading data written with that version until it is officially deprecated. Version 1 predates the stable and experimental numbering convention but remains supported for existing deployments. This is separate from feature maturity: incremental reprocessing and S3 bucket storage are currently in Beta. Storage version 3 is experimental: its layout can change without notice and support can be removed in a future release. If you previously set storage_version: 3, deploy with version 4, which uses the same format marked stable.

Supported Fixes

This table lists all fixes currently supported:

timestamps_iso8601

PowerSync is supposed to encode timestamps according to the ISO-8601 standard. Without this fix, the service encoded timestamps from MongoDB and Postgres source databases incorrectly. To ensure time values from Postgres compare lexicographically, they’re also padded to six digits of accuracy when encoded. Since MongoDB only stores values with an accuracy of milliseconds, only three digits of accuracy are used. For instance, the value 2025-09-22T14:29:30 would be encoded as follows:
  • For Postgres: 2025-09-22 14:29:30 without the fix, 2025-09-22T14:29:30.000000 with the fix applied.
  • For MongoDB: 2025-09-22 14:29:30.000 without the fix, 2025-09-22T14:29:30.000 with the fix applied.
Note that MySQL has never been affected by this issue, and thus behaves the same regardless of the option used.

Configurable Sub-Second Datetime Precision

When the timestamps_iso8601 option is enabled, PowerSync will sync date and time values with a higher precision depending on the source database. You can use the timestamp_max_precision option to configure the actual precision to use. For instance, a Postgres timestamp value would sync as 2025-09-22T14:29:30.000000 by default. If you don’t want that level of precision, you can use the following options to make it sync as 2025-09-22T14:29:30.000:
sync-config.yaml
Valid options for timestamp_max_precision are seconds, milliseconds, microseconds and nanoseconds. When an explicit value is given, all synced time values will use that precision. If a source value has a higher precision, it will be truncated (it is not rounded). If a source value has a lower precision, it will be padded (so setting the option to microseconds with a MongoDB source database will sync values as 2025-09-22T14:29:30.123000, with the last three sub-second digits always being set to zero). If no option is given, the default precision depends on the source database:

versioned_bucket_ids

Sync Rules define buckets, which rows to sync are then assigned to. When you run a full defragmentation or redeploy Sync Rules, the same bucket identifiers are re-used when processing data again. Because the second iteration uses different checksums for the same bucket ids, clients may sync data twice before realizing that something is off and starting from scratch. Applying this fix improves client-side progress estimation and is more efficient, since data would not get downloaded twice. For how bucket identifiers are represented in bucket storage at the persistence layer (including automatic use of versioned bucket names with newer storage formats), see Storage version.

fixed_json_extract

This fixes the json_extract functions as well as the -> and ->> operators in Sync Rules to behave similar to recent SQLite versions: We only split on . if the path starts with $.. For instance, 'json_extract({"foo.bar": "baz"}', 'foo.bar') would evaluate to:
  1. baz with the option enabled.
  2. null with the option disabled.

custom_postgres_types

If you have custom Postgres types in your backend source database schema, older versions of the PowerSync Service would not recognize these values and sync them with the textual wire representation used by Postgres. This is especially noticeable when defining DOMAIN types with e.g. a REAL inner type: The wrapped DOMAIN type should get synced as a real value as well, but it would actually get synced as a string. With this fix applied:
  • DOMAIN TYPEs are synced as their inner type.
  • Array types of custom types get parsed correctly, and sync as a JSON array.
  • Custom types get parsed and synced as a JSON object containing their members.
  • Ranges sync as a JSON object corresponding to the following TypeScript definition:
  • Multi-ranges sync as an array of ranges.

unstable_sqlite_expression_engine

This option is experimental: When enabled, updates to the PowerSync Service might change how rows are processed and this option may be removed in a future version of the Service.
Sync Streams support scalar SQL operators (like +, - and ||) and functions. SQL in Sync Streams should behave exactly as it would in SQLite, but the Service uses a custom implementation which differs from SQLite for some edge cases. To perfectly align the behavior of the Service and SQLite, enabling this option makes the Service use an actual SQLite database to evaluate Sync Streams. Some known issues with the JavaScript evaluator that are fixed by this option are:
  • Exact null handling: NOT NULL evaluates to TRUE without this option, enabling it yields NULL.
  • Without this option, substr() and length() operate on UTF-16 code units. Enabling it makes them operate on Unicode code points.