Common Patterns
These patterns show how to combine Sync Streams features to solve common real-world scenarios.Organization-Scoped Data
For apps where users belong to an organization (or company, team, workspace, etc.), use JWT claims to scope data. Theorg_id in the JWT ensures users only see data from their organization, without needing to pass it from the client.
org_id in the JWT payload when issuing tokens — e.g. { "sub": "user-123", "org_id": "org-456" }. Clients auto-subscribe to org_projects when they connect, so the project list is available offline immediately. Subscribe to project_tasks when the user opens a project:
Role-Based Access
When different users should see different data based on their role, use JWT claims to apply visibility rules. This keeps authorization logic on the server side where it’s secure.org_id and role in the JWT — e.g. { "sub": "user-123", "org_id": "org-456", "role": "admin" }. The role claim is set by your backend so users can’t escalate their own privileges. In this example, Clients auto-subscribe to articles when they connect — no client-side subscription call needed.
Shared Resources
For apps where users can share items with each other (like documents or folders), combine ownership checks with a “shares table” lookup. This syncs both items the user owns and items others have shared with them.my_documents when they connect, so the user’s documents (owned and shared) are available immediately.
Syncing Related Data
When a detail view needs data from multiple tables (like an issue and its comments), use a CTE and multiple queries per stream to define the authorization check once and sync both tables in one subscription.User’s Default or Primary Item
When users have a “default” or “primary” item stored in their profile, you can sync related data automatically without the client needing to know the ID upfront.primary_list_id from the users table, then syncs all todos from that list. When the user changes their primary list in the database, the synced data updates automatically. Clients auto-subscribe to primary_list_todos when they connect — no client-side subscription call needed.
Hierarchical Data
When your data has parent-child relationships across multiple levels, you can traverse the hierarchy using nested subqueries or joins. This is common in apps where access to child records is determined by membership at a higher level. For example, consider an app with organizations, projects, and tasks. Users belong to organizations, and should see all tasks in projects that belong to their organizations:org_tasks when they connect — no client-side subscription call needed.
Many-to-Many Relationships
Many-to-many relationships (like users subscribing to boards) typically use a join table. Sync Streams supportINNER JOINs, so you can traverse these relationships directly without denormalizing your schema.
Consider a social app where users subscribe to message boards:
board_subscriptions to find relevant data: posts in the user’s boards, comments on those posts, and other users sharing those boards.
Unlike with legacy Sync Rules, you don’t need to denormalize your schema or maintain array columns to handle these relationships.
Use Case Examples
Complete configurations for common application types.To-do List App
Sync the list oflists upfront, but only sync todos when the user opens a specific list:
lists when they connect. Subscribe to list_todos when the user opens a list:
Chat Application
Chat apps typically have many conversations but users only view one at a time. Sync the conversation list upfront so users can see all their chats immediately, but load messages on-demand to avoid syncing potentially thousands of messages across all conversations.my_conversations when they connect. Subscribe to conversation_messages when the user opens a conversation:
Project Management App
This example shows a multi-tenant project management app where users can access public projects or projects they’re members of. Each stream that needs “accessible projects” defines a CTE in that stream (Sync Streams do not support a top-levelwith block).
org_id in the JWT — e.g. { "sub": "user-123", "org_id": "org-456" }. Clients auto-subscribe to org_info and projects when they connect. Subscribe to project details when the user opens a project:
Organization Workspace (Using Multiple Queries)
When several tables share the same access pattern, you can group them into a single stream using multiple queries and a CTE. Sync is more efficient and the client only needs to manage one subscription instead of multiple.user_orgs CTE in org_data looks up org membership using auth.user_id(). In project_details, the CTE can include subscription.parameter('project_id') so it both authorizes (user must be in the project’s org) and applies the selected project — the queries then just filter by project_id IN selected_project. Clients auto-subscribe to org_data when they connect. Subscribe to project_details when the user opens a project:
project_details stream uses a CTE and groups tasks, files, and comments for a specific project into a single subscription.
Demo Apps
Working demo apps that demonstrate Sync Streams in action. These show how to combine auto-subscribe streams (for data that should always be available) with on-demand streams (for data loaded when needed).- TypeScript/JavaScript
- Dart
- Kotlin
- Swift
- .NET
Try the
react-supabase-todolist-sync-streams demo app by following the instructions in the README.In this demo:- The app syncs
listsby default, so they’re available immediately and offline (demonstrating auto-subscribe behavior). - The app syncs
todoson demand when a user opens a list (demonstrating subscription parameters). - When the user navigates back to the same list, they won’t see a loading state, because the data is cached locally (demonstrating TTL caching behavior).