JSON and JSONB
The PowerSync Service treats JSON and JSONB columns as text and provides many helpers for working with JSON in Sync Streams (or legacy Sync Rules). Note: Native Postgres arrays, JSON arrays, and JSONB arrays are effectively all equivalent in PowerSync.Postgres
JSON columns are represented as:Sync Streams
- Sync Streams
- Sync Rules (Legacy)
PowerSync treats JSON columns as text. Use The client subscribes once per list (e.g.
json_extract() and other JSON functions in stream queries. Subscribe per list to sync only that list’s todos:db.syncStream('my_json_todos', { list_id: listId }).subscribe()).Client SDK
Schema Add your JSON column as atext column in your client-side schema definition. For advanced update tracking, see Advanced Schema Options.
- Dart
- JavaScript
- .NET
- Rust
trackPreviousValues enabled, compare the previous and new values to process only the changes you care about:
- Dart
- JavaScript
- .NET
- Rust
Arrays
PowerSync treats array columns as JSON text. This means that the SQLite JSON operators can be used on any array columns. Additionally, array membership is supported in Sync Streams (or legacy Sync Rules) so you can sync rows based on whether a parameter value appears in an array column. Note: Native Postgres arrays, JSON arrays, and JSONB arrays are effectively all equivalent in PowerSync.Postgres
Array columns are defined in Postgres using the following syntax:Sync Streams
Array columns are converted to text by the PowerSync Service. A text array as defined above would be synced to clients as the following string:["00000000-0000-0000-0000-000000000000", "12345678-1234-1234-1234-123456789012"]
Array Membership
- Sync Streams
- Sync Rules (Legacy)
Sync rows where a subscription parameter value is in the row’s array column using The client subscribes per list (e.g.
IN:db.syncStream('custom_todos', { list_id: listId }).subscribe()).Client SDK
Schema Add your array column as atext column in your client-side schema definition. For advanced update tracking, see Advanced Schema Options.
- JavaScript
- Dart
- .NET
- Rust
trackPreviousValues enabled, compare the previous and new values to process only the changes you care about:
- JavaScript
- Dart
- .NET
- Rust
Attention Supabase users: Supabase can handle writes with arrays, but you must convert from string to array using
jsonDecode in the connector’s uploadData function. The default implementation of uploadData does not handle complex types like arrays automatically.Custom Types
PowerSync respects Postgres custom types: DOMAIN types sync as their inner type, custom type columns as JSON objects, arrays of custom types as JSON arrays, and ranges (and multi-ranges) as structured JSON. This behavior is the default for Sync Streams. For configuration and legacy behavior, see Compatibility. For type handling in queries, see Types.Postgres
Postgres allows developers to create custom data types for columns. For example:Sync Streams
- Sync Streams
- Sync Rules (Legacy)
The custom type column is serialized as JSON and you can use
json_extract() and other JSON functions in stream queries:Client SDK
Schema Add your custom type column as atext column in your client-side schema definition. For advanced update tracking, see Advanced Schema Options.
- JavaScript
- Dart
- .NET
- Rust
trackPreviousValues enabled, compare the previous and new values to process only the changes you care about:
- JavaScript
- Dart
- .NET
- Rust
Bonus: Mashup
What if we had a column defined as an array of custom types, where a field in the custom type was JSON? Consider the following Postgres schema:Advanced Schema Options to Process Writes
With arrays and JSON fields, it’s common for only part of the value to change during an update. To make handling these writes easier, you can enable advanced schema options that let you track exactly what changed in each row—not just the new state.trackPreviousValues(ortrackPreviousin our JS SDKs): Access previous values for diffing JSON or array fields. Accessible later viaCrudEntry.previousValues.trackMetadata: Adds a_metadatacolumn for storing custom metadata. Value of the column is accessible later viaCrudEntry.metadata.ignoreEmptyUpdates: Skips updates when no data has actually changed.
These advanced schema options were introduced in the following SDK versions:
- Flutter v1.13.0
- React Native v1.20.1
- JavaScript/Web v1.20.1
- Kotlin v1.1.0
- Swift v1.1.0
- Node.js v0.4.0
- .NET v0.0.6-alpha.1