Flutter InstantDB 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 widget
Watch((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 widget
class 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 atomically
await 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 states
class 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 transactions
await db.transact([...db.create('item1', data1)]);
await db.transact([...db.create('item2', data2)]);
await db.transact([...db.create('item3', data3)]);
// Use a single batched transaction
await 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 background
await db.transact([
db.update(todoId, {'completed': true}),
]);
// The UI shows the change instantly, sync happens asynchronouslyAdvanced 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
baseUrl: '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 status
if (!isOnline) {
return OfflineBanner();
}
// Bad: No indication of offline state2. Optimistic UI Updates
Trust InstantDB’s optimistic updates:
// Good: Update immediately, let InstantDB handle sync
await db.transact([db.update(id, newData)]);
// Bad: Wait for server confirmation3. Batch Operations
Group related operations into single transactions:
// Good: Atomic operation
await db.transact([
...db.create('post', postData),
db.update(userId, {'postCount': {'$increment': 1}}),
]);
// Bad: Separate operations that could fail independently4. Monitor Connection
Provide connection status in your UI:
// Always show connection status in critical apps
AppBar(
actions: [
ConnectionStatusIndicator(),
],
)Troubleshooting Sync Issues
Common Issues
- Not Syncing: Check if
syncEnabled: truein 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 logs
config: const InstantConfig(
syncEnabled: true,
verboseLogging: true,
),Network Debugging
Test sync with network conditions:
// Simulate offline mode for testing
db.syncEngine?.disconnect();
// Reconnect
db.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