Flutter InstantDB provides a set of reactive widgets that automatically update when data changes. These widgets integrate seamlessly with Flutter’s widget tree and provide optimized performance.
Core Widgets
InstantProvider
Provides the InstantDB instance to the widget tree using Flutter’s InheritedWidget pattern. This should typically wrap your entire app.
class InstantProvider extends InheritedWidget {
const InstantProvider({
super.key,
required this.db,
required super.child,
});
final InstantDB db;
static InstantDB of(BuildContext context) {
// Returns the InstantDB instance
}
}Parameters:
db(InstantDB): The database instance to providechild(Widget): The child widget tree
Example:
void main() async {
final db = await InstantDB.init(appId: 'your-app-id');
runApp(InstantProvider(db: db, child: MyApp()));
}Watch
Part of the signals_flutter library (re-exported by flutter_instantdb). This widget rebuilds whenever any signal accessed inside its builder function changes value.
class Watch extends StatelessWidget {
const Watch(this.builder, {super.key});
final Widget Function(BuildContext context) builder;
}Example:
Watch((context) {
final db = InstantProvider.of(context);
final isOnline = db.isOnline.value; // Accessing .value creates a dependency
return Text(isOnline ? 'Connected' : 'Disconnected');
});Query Widgets
InstantBuilder
The primary widget for building UI based on InstaQL queries. It handles loading and error states automatically.
class InstantBuilder extends StatelessWidget {
const InstantBuilder({
required this.query,
required this.builder,
this.errorBuilder,
this.loadingBuilder,
});
}Properties:
query(Map<String, dynamic>): The InstaQL querybuilder(Widget Function(BuildContext, Map<String, dynamic>)): Called when data is availableloadingBuilder(Widget Function(BuildContext)?): Optional custom loading UIerrorBuilder(Widget Function(BuildContext, String)?): Optional custom error UI
Example:
InstantBuilder(
query: {'goals': {}},
builder: (context, data) {
final goals = data['goals'] as List;
return ListView(children: [ ... ]);
},
)InstantBuilderTyped<T>
A generic version of InstantBuilder that includes a transformer function to convert raw map data into your own model classes.
Example:
InstantBuilderTyped<List<Todo>>(
query: {'todos': {}},
transformer: (data) => (data['todos'] as List)
.map((json) => Todo.fromJson(json))
.toList(),
builder: (context, todos) {
return TodoList(todos: todos);
},
)InstantBuilder.list / InstantBuilder.single
Convenience static methods for common query patterns.
// Fetch a list of entities
InstantBuilder.list(
entityType: 'todos',
where: {'completed': false},
builder: (context, todos) => ...,
)
// Fetch a single entity by ID
InstantBuilder.single(
entityType: 'users',
id: 'user-123',
builder: (context, user) => ...,
)Authentication Widgets
AuthBuilder
Rebuilds when the authentication state changes.
AuthBuilder(
builder: (context, user) {
if (user == null) return Text('Not logged in');
return Text('Logged in as ${user.email}');
},
)AuthGuard
A higher-level widget that shows a child if the user is authenticated, or a fallback (or loginBuilder) if they are not.
AuthGuard(
fallback: LoadingScreen(),
loginBuilder: (context) => LoginScreen(),
child: DashboardScreen(),
)Connection Widgets
ConnectionStatusBuilder
Provides periodic updates on the database connection status.
ConnectionStatusBuilder(
builder: (context, isOnline) {
return Icon(
isOnline ? Icons.cloud_done : Icons.cloud_off,
color: isOnline ? Colors.green : Colors.red,
);
},
)State Management Hooks
useInstantQuery
A function that returns a Signal<QueryResult> for a given query. Useful inside StatefulWidget or other places where you want to manage the signal lifecycle yourself.
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late Signal<QueryResult> query;
@override
void didChangeDependencies() {
super.didChangeDependencies();
query = useInstantQuery(context, {'messages': {}});
}
@override
Widget build(BuildContext context) {
return Watch((context) {
final result = query.value;
// ... build UI
});
}
}