The InstantDB class is the main entry point for interacting with your InstantDB database. It provides methods for initialization, queries, transactions, authentication, and real-time synchronization.
Initialization
InstantDB.init()
Initialize a new InstantDB instance.
static Future<InstantDB> init({
required String appId,
InstantConfig config = const InstantConfig(),
})Parameters:
appId(String): Your InstantDB application IDconfig(InstantConfig, optional): Configuration options
Returns: Future<InstantDB> - The initialized database instance
Example:
final db = await InstantDB.init(
appId: 'your-app-id',
config: const InstantConfig(
syncEnabled: true,
verboseLogging: false,
),
);InstantConfig
Configuration options for InstantDB initialization.
class InstantConfig {
const InstantConfig({
this.persistenceDir,
this.syncEnabled = true,
this.baseUrl = 'https://api.instantdb.com',
this.maxCacheSize = 50 * 1024 * 1024, // 50MB
this.reconnectDelay = const Duration(seconds: 1),
this.verboseLogging = false,
});
final String? persistenceDir;
final bool syncEnabled;
final String baseUrl;
final int maxCacheSize;
final Duration reconnectDelay;
final bool verboseLogging;
}Properties:
persistenceDir(String?): Custom directory for SQLite database storagesyncEnabled(bool): Enable real-time synchronization (default:true)baseUrl(String): Custom API endpoint URL (default:https://api.instantdb.com)maxCacheSize(int): Maximum size of the local database cache in bytes (default: 50MB)reconnectDelay(Duration): Delay between reconnection attempts (default: 1 second)verboseLogging(bool): Enable detailed debug logging (default:false)
Core Properties
isReady
A reactive signal indicating if the database is initialized and ready for use.
ReadonlySignal<bool> get isReadyExample:
if (db.isReady.value) {
print('Database is ready');
}isOnline
A reactive signal indicating if the database is currently connected to the sync server.
ReadonlySignal<bool> get isOnlineExample:
Watch((context) {
final online = db.isOnline.value;
return Text(online ? 'Connected' : 'Disconnected');
});appId
Get the application ID for this database instance.
String get appIdReturns: String - The application ID
Example:
print('Database app ID: ${db.appId}');auth
Access the authentication manager.
AuthManager get authReturns: AuthManager - The authentication manager instance
Example:
final currentUser = db.auth.currentUser.value;
if (currentUser != null) {
print('User: ${currentUser.email}');
}presence
Access the presence manager for real-time collaboration.
PresenceManager get presenceReturns: PresenceManager - The presence manager instance
Example:
final room = db.presence.joinRoom('chat-room');
await room.setPresence({'status': 'online'});syncEngine
Access the internal synchronization engine. Note that most synchronization logic is handled automatically through db.query and db.transact.
SyncEngine get syncEngineReturns: SyncEngine - The sync engine instance
Query Methods
query()
Create a reactive query that updates automatically when data changes. This is the preferred method for getting data.
Signal<QueryResult> query(Map<String, dynamic> query, {bool syncedOnly = false})Parameters:
query(Map<String, dynamic>): The InstaQL query objectsyncedOnly(bool, optional): If true, only returns entities that sync to cloud (excludes local-only entities)
Returns: Signal<QueryResult> - A reactive signal containing query results
Example:
final todosSignal = db.query({
'todos': {
'where': {'completed': false},
'orderBy': {'createdAt': 'desc'},
'limit': 20,
},
});subscribeQuery()
Alias for query(), kept for API compatibility.
Signal<QueryResult> subscribeQuery(Map<String, dynamic> query)Example:
final todosSignal = db.subscribeQuery({
'todos': {
'where': {'completed': false},
'orderBy': {'createdAt': 'desc'},
'limit': 20,
},
});
// Use in reactive widgets
Watch((context) {
final result = todosSignal.value;
final todos = result.data?['todos'] ?? [];
return TodoList(todos: todos);
});queryOnce()
Execute a one-time query without creating a subscription.
Future<QueryResult> queryOnce(Map<String, dynamic> query, {bool syncedOnly = false})Parameters:
query(Map<String, dynamic>): The InstaQL query objectsyncedOnly(bool, optional): If true, only returns entities that sync to cloud
Returns: Future<QueryResult> - The query result
Example:
final result = await db.queryOnce({
'users': {
'where': {'role': 'admin'},
'limit': 5,
},
});
final adminUsers = result.data?['users'] ?? [];
print('Found ${adminUsers.length} admin users');Transaction Methods
transact()
Execute a transaction with a list of operations or transaction chunk.
Future<TransactionResult> transact(dynamic transaction)Parameters:
transaction(List<Operation>orTransactionChunk): The operations to execute
Returns: Future<TransactionResult> - The transaction result
Example:
// With list of operations
await db.transact([
...db.create('todos', {
'id': db.id(),
'text': 'Learn InstantDB',
'completed': false,
}),
]);
// With transaction chunk (new tx API)
await db.transact(
db.tx['todos'][todoId].update({'completed': true})
);transactChunk() (Deprecated)
Execute a transaction chunk. Use transact() instead.
@Deprecated('Use transact() instead')
Future<TransactionResult> transactChunk(TransactionChunk chunk)create()
Create a new entity operation.
List<Operation> create(String entityType, Map<String, dynamic> data)Parameters:
entityType(String): The type of entity to createdata(Map<String, dynamic>): The entity data
Returns: List<Operation> - List containing the create operation
Example:
final operations = db.create('posts', {
'id': db.id(),
'title': 'Hello World',
'content': 'This is my first post',
'authorId': userId,
'createdAt': DateTime.now().millisecondsSinceEpoch,
});
await db.transact(operations);update()
Create an update entity operation.
Operation update(String entityId, Map<String, dynamic> data)Parameters:
entityId(String): The ID of the entity to updatedata(Map<String, dynamic>): The data to update
Returns: Operation - The update operation
Example:
await db.transact([
db.update(postId, {
'title': 'Updated Title',
'updatedAt': DateTime.now().millisecondsSinceEpoch,
}),
]);delete()
Create a delete entity operation.
Operation delete(String entityId)Parameters:
entityId(String): The ID of the entity to delete
Returns: Operation - The delete operation
Example:
await db.transact([
db.delete(postId),
]);merge()
Create a deep merge operation.
Operation merge(String entityId, Map<String, dynamic> data)Parameters:
entityId(String): The ID of the entity to mergedata(Map<String, dynamic>): The data to deep merge
Returns: Operation - The merge operation
Example:
await db.transact([
db.merge(userId, {
'preferences': {
'theme': 'dark',
'notifications': {'email': false},
},
}),
]);link()
Create a link operation between entities.
Operation link(String fromId, String linkName, String toId)Parameters:
fromId(String): The source entity IDlinkName(String): The name of the link relationshiptoId(String): The target entity ID
Returns: Operation - The link operation
Example:
await db.transact([
db.link(userId, 'posts', postId),
]);unlink()
Create an unlink operation between entities.
Operation unlink(String fromId, String linkName, String toId)Parameters:
fromId(String): The source entity IDlinkName(String): The name of the link relationshiptoId(String): The target entity ID
Returns: Operation - The unlink operation
Example:
await db.transact([
db.unlink(userId, 'posts', postId),
]);Transaction API (tx namespace)
tx
Access the new transaction API namespace for fluent operations.
TransactionNamespace get txReturns: TransactionNamespace - The transaction namespace
Example:
// Fluent API for complex operations
await db.transact(
db.tx['users'][userId]
.update({'name': 'New Name'})
.link({'posts': [postId]})
.merge({
'preferences': {'theme': 'dark'},
})
);Utility Methods
id()
Generate a new UUID for entity IDs.
String id()Returns: String - A new UUID string
Example:
final newId = db.id();
print('Generated ID: $newId'); // e.g., "123e4567-e89b-12d3-a456-426614174000"
await db.transact([
...db.create('items', {
'id': newId,
'name': 'New Item',
}),
]);lookup()
Create a lookup reference for referencing entities by attribute instead of ID.
LookupRef lookup(String entityType, String attribute, dynamic value)Parameters:
entityType(String): The type of entity to lookupattribute(String): The attribute to match againstvalue(dynamic): The value to match
Returns: LookupRef - A lookup reference object
Example:
// Reference user by email instead of ID
await db.transact([
...db.create('posts', {
'id': db.id(),
'title': 'Hello World',
'authorId': lookup('users', 'email', 'john@example.com'),
}),
]);
// Use in queries
final posts = db.subscribeQuery({
'posts': {
'where': {
'author': lookup('users', 'email', 'john@example.com'),
},
},
});Authentication Helpers
getAuth()
Get the current authentication state (one-time check).
AuthUser? getAuth()Returns: AuthUser? - The current user, or null if not authenticated
Example:
final currentUser = db.getAuth();
if (currentUser != null) {
print('Logged in as: ${currentUser.email}');
} else {
print('Not logged in');
}subscribeAuth()
Get a stream of authentication state changes.
Stream<AuthUser?> subscribeAuth()Returns: Stream<AuthUser?> - A stream of auth user state
Example:
db.subscribeAuth().listen((user) {
if (user != null) {
print('User signed in: ${user.email}');
} else {
print('User signed out');
}
});getAnonymousUserId()
Get or generate an anonymous user ID for presence and collaboration.
String getAnonymousUserId()Returns: String - An anonymous user ID
Example:
final anonymousId = db.getAnonymousUserId();
final room = db.presence.joinRoom('public-room', initialPresence: {
'userId': anonymousId,
'userName': 'Guest ${anonymousId.substring(0, 4)}',
});Lifecycle Methods
dispose()
Clean up database resources and connections.
Future<void> dispose()Returns: Future<void>
Example:
@override
void dispose() {
super.dispose();
// Clean up database when app is disposed
db.dispose();
}Error Handling
All InstantDB methods can throw InstantException for database-related errors:
try {
await db.transact([
...db.create('invalid', {}), // Missing required fields
]);
} on InstantException catch (e) {
print('InstantDB Error: ${e.code}');
print('Message: ${e.message}');
// Handle specific error types
switch (e.code) {
case 'validation_error':
// Handle validation errors
break;
case 'network_error':
// Handle network issues
break;
case 'auth_error':
// Handle authentication errors
break;
}
} catch (e) {
print('Unexpected error: $e');
}Complete Example
Here’s a complete example showing common InstantDB operations:
class TodoService {
final InstantDB db;
TodoService(this.db);
// Get reactive todos
Signal<QueryResult> getTodos({bool? completed}) {
return db.subscribeQuery({
'todos': {
if (completed != null) 'where': {'completed': completed},
'orderBy': {'createdAt': 'desc'},
},
});
}
// Create a new todo
Future<void> createTodo({
required String text,
bool completed = false,
}) async {
await db.transact([
...db.create('todos', {
'id': db.id(),
'text': text,
'completed': completed,
'createdAt': DateTime.now().millisecondsSinceEpoch,
'userId': db.auth.currentUser.value?.id,
}),
]);
}
// Update todo using new tx API
Future<void> updateTodo(String todoId, {String? text, bool? completed}) async {
final updates = <String, dynamic>{};
if (text != null) updates['text'] = text;
if (completed != null) updates['completed'] = completed;
updates['updatedAt'] = DateTime.now().millisecondsSinceEpoch;
await db.transact(
db.tx['todos'][todoId].update(updates)
);
}
// Delete todo
Future<void> deleteTodo(String todoId) async {
await db.transact([db.delete(todoId)]);
}
// Get todos by user email (using lookup)
Signal<QueryResult> getTodosByUser(String email) {
return db.subscribeQuery({
'todos': {
'where': {
'user': lookup('users', 'email', email),
},
},
});
}
// Bulk operations
Future<void> markAllCompleted() async {
final result = await db.queryOnce({
'todos': {'where': {'completed': false}},
});
final todos = (result.data?['todos'] as List? ?? [])
.cast<Map<String, dynamic>>();
final operations = todos.map((todo) =>
db.update(todo['id'], {'completed': true})
).toList();
if (operations.isNotEmpty) {
await db.transact(operations);
}
}
}Next Steps
Explore specific API areas:
- Transactions API - Detailed transaction and operation methods
- Queries API - Advanced querying and InstaQL syntax
- Presence API - Real-time collaboration methods
- Flutter Widgets - Reactive UI components
- Types Reference - Complete type definitions