WebSocket Synchronization
InstantDB Flutter provides real-time synchronization across all connected clients using WebSocket connections. Changes are propagated instantly with conflict resolution and offline support.
Enabling Sync
Enable real-time synchronization during database initialization:
final db = await InstantDB.init( appId: 'your-app-id', config: const InstantConfig( syncEnabled: true, // Enable real-time sync verboseLogging: false, // Set to true for detailed sync logs ),);
Connection Status
Monitor the connection status to provide user feedback:
// Using a reactive widgetWatch((context) { final syncEngine = db.syncEngine; final isConnected = syncEngine?.connectionStatus.value ?? false;
return Row( children: [ Icon( isConnected ? Icons.cloud_done : Icons.cloud_off, color: isConnected ? Colors.green : Colors.grey, ), Text(isConnected ? 'Connected' : 'Offline'), ], );});
// Or create a custom connection status widgetclass ConnectionStatusIndicator extends StatelessWidget { @override Widget build(BuildContext context) { final db = InstantProvider.of(context);
return Watch((context) { final isOnline = db.syncEngine?.connectionStatus.value ?? false;
return AnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: isOnline ? Colors.green : Colors.orange, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( isOnline ? Icons.wifi : Icons.wifi_off, size: 16, color: Colors.white, ), const SizedBox(width: 4), Text( isOnline ? 'Online' : 'Offline', style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, ), ), ], ), ); }); }}
How Sync Works
Differential Sync
InstantDB uses differential synchronization to efficiently sync only the changes:
- Local Changes: When you make local changes, they’re applied immediately (optimistic updates)
- Sync Queue: Changes are queued for synchronization with the server
- WebSocket Transmission: Changes are sent via WebSocket in real-time
- Server Processing: Server processes and broadcasts changes to other clients
- Conflict Resolution: Automatic handling of concurrent modifications
Transaction Integrity
All operations maintain transaction integrity during sync:
// This transaction will be synced atomicallyawait db.transact([ ...db.create('posts', { 'id': db.id(), 'title': 'New Post', 'authorId': userId, }), db.update(userId, { 'postCount': {'$increment': 1}, }),]);
Sync Events
Monitor sync events for debugging or user feedback:
// Listen to sync engine events (if available)db.syncEngine?.onConnectionChange.listen((isConnected) { print('Connection status changed: $isConnected');
if (isConnected) { // Connection restored - sync pending changes showSnackBar('Connection restored'); } else { // Connection lost - work offline showSnackBar('Working offline'); }});
Handling Offline/Online Transitions
InstantDB handles offline scenarios gracefully:
Offline Behavior
When offline, InstantDB:
- Stores all changes locally in SQLite
- Continues to serve queries from local data
- Queues mutations for later synchronization
- Provides immediate UI updates (optimistic)
Coming Back Online
When connection is restored:
- Pending transactions are automatically synced
- Server changes are downloaded and applied
- Conflicts are resolved automatically
- UI updates reflect the synchronized state
// Example of handling online/offline statesclass OfflineAwareWidget extends StatelessWidget { @override Widget build(BuildContext context) { final db = InstantProvider.of(context);
return Watch((context) { final isOnline = db.syncEngine?.connectionStatus.value ?? false;
return Column( children: [ if (!isOnline) Container( width: double.infinity, padding: const EdgeInsets.all(8), color: Colors.orange, child: const Text( 'Working offline - changes will sync when connected', textAlign: TextAlign.center, style: TextStyle(color: Colors.white), ), ),
// Your main content InstantBuilder( query: {'todos': {}}, builder: (context, result) { // Data is always available, even offline return TodoList(todos: result.data!['todos']); }, ), ], ); }); }}
Sync Performance
Batching Operations
For better performance, batch multiple operations:
// Instead of multiple separate transactionsawait db.transact([...db.create('item1', data1)]);await db.transact([...db.create('item2', data2)]);await db.transact([...db.create('item3', data3)]);
// Use a single batched transactionawait db.transact([ ...db.create('item1', data1), ...db.create('item2', data2), ...db.create('item3', data3),]);
Optimistic Updates
InstantDB provides optimistic updates by default:
// UI updates immediately, then syncs in backgroundawait db.transact([ db.update(todoId, {'completed': true}),]);
// The UI shows the change instantly, sync happens asynchronously
Advanced Sync Configuration
Custom Sync Settings
Configure sync behavior during initialization:
final db = await InstantDB.init( appId: 'your-app-id', config: const InstantConfig( syncEnabled: true,
// Custom WebSocket URL (optional) websocketUrl: 'wss://custom.instantdb.com/ws',
// Enable detailed logging for debugging verboseLogging: true,
// Custom API endpoint apiUrl: 'https://custom.instantdb.com', ),);
Sync Debugging
Enable verbose logging to debug sync issues:
final db = await InstantDB.init( appId: 'your-app-id', config: const InstantConfig( syncEnabled: true, verboseLogging: true, // Detailed sync logs ),);
This will log:
- WebSocket connection events
- Transaction synchronization
- Conflict resolution
- Network errors and retries
Best Practices
1. Handle Connection States
Always provide feedback for offline states:
// Good: Show connection statusif (!isOnline) { return OfflineBanner();}
// Bad: No indication of offline state
2. Optimistic UI Updates
Trust InstantDB’s optimistic updates:
// Good: Update immediately, let InstantDB handle syncawait db.transact([db.update(id, newData)]);
// Bad: Wait for server confirmation
3. Batch Operations
Group related operations into single transactions:
// Good: Atomic operationawait db.transact([ ...db.create('post', postData), db.update(userId, {'postCount': {'$increment': 1}}),]);
// Bad: Separate operations that could fail independently
4. Monitor Connection
Provide connection status in your UI:
// Always show connection status in critical appsAppBar( actions: [ ConnectionStatusIndicator(), ],)
Troubleshooting Sync Issues
Common Issues
- Not Syncing: Check if
syncEnabled: true
in config - Slow Sync: Check network connection and server status
- Conflicts: Review conflict resolution logs
- Memory Issues: Ensure proper disposal of database instances
Debug Logging
Enable verbose logging to diagnose issues:
// Add this to see detailed sync logsconfig: const InstantConfig( syncEnabled: true, verboseLogging: true,),
Network Debugging
Test sync with network conditions:
// Simulate offline mode for testingdb.syncEngine?.disconnect();
// Reconnectdb.syncEngine?.connect();
Next Steps
Learn more about InstantDB’s real-time features:
- Presence System - Real-time collaboration
- Collaborative Features - Building multi-user apps
- Performance Tips - Optimizing sync performance
- Troubleshooting - Debugging sync issues