Live Cells brings true reactivity to your Dart & Flutter data layer.
Declare cells, compose them, and let your UI respond automatically—no boilerplate, no manual listeners, no dispose().
flutter pub add live_cells
Why Live Cells
Everything you need to write expressive, composable state logic without fighting the framework.
Observers are notified automatically when cell values change. Define a computed cell once and it stays in sync forever.
Unique among reactive libraries: data can flow in both directions. Bind a text field to a number cell with a single line.
Cells manage their own lifecycle. No more forgetting to remove listeners or call dispose()—memory cleans itself up.
Write a + b and get a cell whose value is always the sum. Functional composition, no listener wiring.
Drop-in reactive widgets—LiveSwitch, LiveTextField, CellWidget—bind directly to cells with no state management ceremony.
Persist and restore app state with minimal boilerplate. Cells that survive process death, with no extra wiring.
Before & After
See the difference when reactive state is a first-class citizen of your data layer.
final a = ValueNotifier<int>(0); final b = ValueNotifier<int>(1); late final sum = ValueNotifier<int>(0); // Wire listeners manually void _updateSum() { sum.value = a.value + b.value; print('${a.value} + ${b.value} = ${sum.value}'); } // Remember to add AND remove a.addListener(_updateSum); b.addListener(_updateSum); ... @override void dispose() { a.removeListener(_updateSum); b.removeListener(_updateSum); a.dispose(); b.dispose(); sum.dispose(); super.dispose(); }
final a = MutableCell(0); final b = MutableCell(1); // Reactive expression — just works final sum = a + b; // Observe — no manual wiring ValueCell.watch(() { print('${a()} + ${b()} = ${sum()}'); }); // No dispose() needed. // Ever.
Core Concepts
The cell is the only primitive. Master it and you have mastered the library.
The entry point to reactivity. Set a value; observers fire automatically.
final count = MutableCell(0); count.value++; // triggers observers
Derive state from other cells with plain expressions or ValueCell.computed.
final doubled = count * 2.cell; // or final label = ValueCell.computed( () => 'Count: ${count()}', );
Bind a numeric cell to a text field. Changes flow both ways automatically.
final n = MutableCell<num>(0); LiveTextField( content: n.mutableString(), );
Rebuild only the widgets that need to—no setState, no provider lookup.
final count = MutableCell(0); final isEnabled = MutableCell(true); ... CellWidget.builder(() => Text('${count()}') ); ... LiveSwitch(value: isEnabled);
Await futures held in cells. Computed cells propagate loading state too.
final isLoading = (c1, c2).isCompleted.not(); final sum = ValueCell.computed(() { final (a, b) = (c1, c2).wait(); return a + b; });
Exceptions propagate through cell chains. Handle them where it makes sense.
final str = MutableCell('0'); final n = ValueCell.computed( () => int.parse(str()), ); final valid = (n > 0.cell) .onError(false.cell);
Advantages
ChangeNotifierLive Cells solves the friction points you've accepted as normal in Flutter state management.
No forced architecture. Use as much or as little of Live Cells as you need. Integrate incrementally.
The .listenable property wraps any cell as a ValueListenable—use it wherever Flutter expects one.
Need the last value of a cell? Just use cell.previous—it's a cell too.
live_cell_extension generates property accessors so you can use cell syntax on your own model classes.
Used by developers building with Flutter
Using Live Cells in your app? Open a PR to add it here →
Supported by
This project is BSD-licensed and maintained in spare time. Sponsor on GitHub →
Quick Start
Three steps from zero to reactive Flutter app.
flutter pub add live_cells — or add live_cells: ^0.34.0 to your pubspec.yaml.
Import package:live_cells/live_cells.dart and declare your state as MutableCell instances at the top of your logic layer.
Wrap rebuilding UI in CellWidget.builder, or swap Flutter widgets for their Live* equivalents. Done.